<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>汇编语言笔记 | Mox的笔记库</title><meta name="keywords" content="Working"><meta name="author" content="MocusEZ"><meta name="copyright" content="MocusEZ"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="2021年寒假的任务，希望能为以后学习奠定基础">
<meta property="og:type" content="article">
<meta property="og:title" content="汇编语言笔记">
<meta property="og:url" content="https://www.mocusez.site/posts/79b6.html">
<meta property="og:site_name" content="Mox的笔记库">
<meta property="og:description" content="2021年寒假的任务，希望能为以后学习奠定基础">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://cdn.fuhao321.com/uploads/2009/1-200Z20S45cM.jpg">
<meta property="article:published_time" content="2021-02-11T13:10:26.000Z">
<meta property="article:modified_time" content="2021-02-11T13:11:26.000Z">
<meta property="article:author" content="MocusEZ">
<meta property="article:tag" content="Working">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://cdn.fuhao321.com/uploads/2009/1-200Z20S45cM.jpg"><link rel="shortcut icon" href="/img/title.jpg"><link rel="canonical" href="https://www.mocusez.site/posts/79b6"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?c85c9eaebc158345532b86397a6dded9";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: '汇编语言笔记',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2021-02-11 21:11:26'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><meta name="generator" content="Hexo 6.2.0"><link rel="alternate" href="/atom.xml" title="Mox的笔记库" type="application/atom+xml">
</head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/head.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">61</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">0</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">8</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链&amp;私人收藏</span></a></div><div class="menus_item"><a class="site-page" href="/board/"><i class="fa-fw fas fa-user"></i><span> 留言板</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://cdn.fuhao321.com/uploads/2009/1-200Z20S45cM.jpg')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">Mox的笔记库</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 归档</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链&amp;私人收藏</span></a></div><div class="menus_item"><a class="site-page" href="/board/"><i class="fa-fw fas fa-user"></i><span> 留言板</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">汇编语言笔记</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2021-02-11T13:10:26.000Z" title="发表于 2021-02-11 21:10:26">2021-02-11</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2021-02-11T13:11:26.000Z" title="更新于 2021-02-11 21:11:26">2021-02-11</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E6%97%A5%E5%B8%B8%E7%AC%94%E8%AE%B0/">日常笔记</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="汇编语言笔记"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="汇编语言笔记"><a href="#汇编语言笔记" class="headerlink" title="汇编语言笔记"></a>汇编语言笔记</h1><p>Assemby Language (MASM)</p>
<p>涉及操作系统，编写编译器</p>
<p>以<strong>机器级</strong>思维方式处理编程问题</p>
<p>课程配套资料：<a target="_blank" rel="noopener external nofollow noreferrer" href="http://asmirvine.com/">http://asmirvine.com/</a></p>
<p><a target="_blank" rel="noopener external nofollow noreferrer" href="https://jingyan.baidu.com/article/e8cdb32be1940437042bad5c.html">VS2019汇编环境配置</a></p>
<p>操作数不是数</p>
<p>irvine32配置（作者写的……作者是Kip Irvine）</p>
<p><a target="_blank" rel="noopener external nofollow noreferrer" href="https://blog.csdn.net/fuhanghang/article/details/112408348">https://blog.csdn.net/fuhanghang/article/details/112408348</a></p>
<p>测试irvine的验证代码</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">; This program adds and subtracts 32-bit integers</span><br><span class="line">; and stores the sum in a variable.</span><br><span class="line"> </span><br><span class="line">INCLUDE Irvine32.inc</span><br><span class="line"> </span><br><span class="line">.data</span><br><span class="line">val1     dword  10000h</span><br><span class="line">val2     dword  40000h</span><br><span class="line">val3     dword  20000h</span><br><span class="line">finalVal dword  ?</span><br><span class="line"> </span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line"> </span><br><span class="line">    mov    eax,val1            ; start with 10000h</span><br><span class="line">    add    eax,val2            ; add 40000h</span><br><span class="line">    sub    eax,val3            ; subtract 20000h</span><br><span class="line">    mov    finalVal,eax        ; store the result (30000h)</span><br><span class="line">    call    DumpRegs            ; display the registers</span><br><span class="line"> </span><br><span class="line">    exit</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>有的网站已经书的内容搬运过去了</p>
<p><a target="_blank" rel="noopener external nofollow noreferrer" href="http://c.biancheng.net/view/3295.html">http://c.biancheng.net/view/3295.html</a></p>
<p><a target="_blank" rel="noopener external nofollow noreferrer" href="https://blog.csdn.net/peiwang245/article/details/98108021">X86汇编常见的寄存器</a></p>
<p>offset 偏移量</p>
<h2 id="1基本概念"><a href="#1基本概念" class="headerlink" title="1基本概念"></a>1基本概念</h2><h3 id="1-2-虚拟机概念"><a href="#1-2-虚拟机概念" class="headerlink" title="1.2 虚拟机概念"></a>1.2 虚拟机概念</h3><p>L0 电子电路</p>
<p>L1 数字逻辑</p>
<p>L2 指令集架构（IAS）-机器语言</p>
<p>L3 汇编语言</p>
<p>L4 高级语言</p>
<p>层与层之间<strong>解释</strong>或<strong>翻译</strong></p>
<p><strong>解释</strong>在执行前需要译码(解释程序一定是L0)</p>
<p><strong>翻译</strong>将L1层程序转为L0层程序</p>
<p><strong>虚拟机</strong>可以定义为一个<strong>软件程序</strong>，用来模拟物理或虚拟计算机</p>
<p>VM1执行L1语言编写的命令</p>
<p>Java程序相对而言独立于系统</p>
<h3 id="1-3-数据表示"><a href="#1-3-数据表示" class="headerlink" title="1.3 数据表示"></a>1.3 数据表示</h3><p>必须善于检查<strong>内存和寄存器</strong></p>
<h4 id="1-3-1-二进制整数"><a href="#1-3-1-二进制整数" class="headerlink" title="1.3.1 二进制整数"></a>1.3.1 二进制整数</h4><p><strong>位</strong>自右向左，从0编号</p>
<p>左边MSB（最高有效位）</p>
<p>右边LSB（least significant bit）(最低有效位)</p>
<p>二进制与十进制间的转换</p>
<h4 id="1-3-2-二进制加法"><a href="#1-3-2-二进制加法" class="headerlink" title="1.3.2 二进制加法"></a>1.3.2 二进制加法</h4><p>加法时要预留存储位</p>
<h4 id="1-3-3-整数储存大小"><a href="#1-3-3-整数储存大小" class="headerlink" title="1.3.3 整数储存大小"></a>1.3.3 整数储存大小</h4><p>所有存储的基本单位都是字节</p>
<p>一个字节8位，有字（两个字节），双字，四字</p>
<h4 id="1-3-4-十六进制整数"><a href="#1-3-4-十六进制整数" class="headerlink" title="1.3.4 十六进制整数"></a>1.3.4 十六进制整数</h4><p>二进制1111 即 十六进制的 F </p>
<p>提供一种简便的方式阅读大的二进制数</p>
<h4 id="1-3-5-十六进制加法"><a href="#1-3-5-十六进制加法" class="headerlink" title="1.3.5 十六进制加法"></a>1.3.5 十六进制加法</h4><p><strong>内存地址用十六进制表示</strong></p>
<p>更换十进制加法的基数，求16的余数，然后按十进制的方向相加</p>
<h4 id="1-3-6-有符号二进制整数"><a href="#1-3-6-有符号二进制整数" class="headerlink" title="1.3.6  有符号二进制整数"></a>1.3.6  有符号二进制整数</h4><p>补码：按位取反后加1</p>
<p>十六进制一样适用，但每个位变为<strong>15减去数字</strong></p>
<h4 id="1-3-7-二进制减法"><a href="#1-3-7-二进制减法" class="headerlink" title="1.3.7 二进制减法"></a>1.3.7 二进制减法</h4><h4 id="1-3-8-字符存储"><a href="#1-3-8-字符存储" class="headerlink" title="1.3.8 字符存储"></a>1.3.8 字符存储</h4><p>ASCII码为十六进制</p>
<p>ASCII只用字节的低7位，<strong>最高位被用来创建专有字符集</strong></p>
<p>ASCII字符串结尾处有一个为0的字节 ，是\0（反斜杠）</p>
<p>ASCII控制字符好像是一种很牛逼的东西，输出控制字符会执行一些预定义的动作</p>
<p><strong>二进制整数</strong>是指以原始格式保存在内存中得整数，以备计算</p>
<p><strong>数字字符串</strong>是一串ASCII字符</p>
<h3 id="1-4-布尔表达式"><a href="#1-4-布尔表达式" class="headerlink" title="1.4 布尔表达式"></a>1.4 布尔表达式</h3><p>就是 与 或 非</p>
<p>OR AND NOT</p>
<p>NOT具有最高优先级</p>
<p>AND和NOT级别一样</p>
<h3 id="1-5-本章小结"><a href="#1-5-本章小结" class="headerlink" title="1.5 本章小结"></a>1.5 本章小结</h3><p>KEY！！！！</p>
<p><strong>汇编器</strong>是一种程序，将<strong>汇编语言</strong>转化为<strong>机器语言</strong></p>
<p><strong>链接器</strong>将生成的单个文件组合成可<strong>执行程序</strong></p>
<p>还有就是<strong>调试器</strong>，用于追踪程序</p>
<p>汇编语言和机器语言是<strong>一对一</strong>的关系</p>
<h2 id="2-x86处理器架构"><a href="#2-x86处理器架构" class="headerlink" title="2 x86处理器架构"></a>2 x86处理器架构</h2><h3 id="2-1-一般概念"><a href="#2-1-一般概念" class="headerlink" title="2.1 一般概念"></a>2.1 一般概念</h3><h4 id="2-1-1-基本微机设计"><a href="#2-1-1-基本微机设计" class="headerlink" title="2.1.1 基本微机设计"></a>2.1.1 基本微机设计</h4><p>寄存器，高频时钟，控制单元，算数逻辑单元</p>
<p>时钟：<strong>CPU内部操作</strong>与<strong>系统其他组件</strong>进行同步</p>
<p>控制单元：协调参与机器指令执行</p>
<p>算数逻辑单元：执行<strong>算数运算</strong>和<strong>逻辑运算</strong></p>
<p><strong>内存存储单元</strong>用于程序运行时<strong>保存指令与数据</strong></p>
<p>这东西不是RAM</p>
<p>接受CPU数据请求，将数据从RAM运往CPU</p>
<p>？？？</p>
<p>ALU是<strong>算数逻辑单元</strong></p>
<p>总线是<strong>并行线</strong></p>
<p>数据总线  CPU与内存之间<strong>传输指令和数据</strong></p>
<p>IO总线  CPU与系统输入&#x2F;输出设备之间传输<strong>数据</strong></p>
<p>控制总线 用二进制信号对所有<strong>连接在总线上的设备的行为进行同步</strong></p>
<p>地址总线  <strong>保持</strong>指令和数据的地址（Cpu和内存间通信时）</p>
<p>由于不同组件组件的运行速度存在差异</p>
<p>访问内存指令往往需要空<strong>时钟周期</strong></p>
<p>也就是<strong>等待状态</strong></p>
<h4 id="2-1-2-指令执行周期"><a href="#2-1-2-指令执行周期" class="headerlink" title="2.1.2 指令执行周期"></a>2.1.2 指令执行周期</h4><p>1.CPU从指定内存区域（指令队列）获得指令，之后立即增加<strong>指令指针</strong>的值</p>
<p>2.CPU对指令的<strong>二进制位模式</strong>进行编码???</p>
<p>3.如果有操作数，CPU就从寄存器和内存中取得操作数，有时还包括地址计算</p>
<p>4.CPU使用从步骤三获得的操作数，CPU执行指令，同时更新<strong>状态位</strong></p>
<p>如<strong>零标志</strong>（Zero），进位标志（Carry）和溢出标志（Overflow）</p>
<p>5.如果有输出操作数的话，CPU需要对其存放</p>
<p>简化为三个步骤：取值，译码，执行</p>
<p>图2-2是什么东西？？</p>
<h4 id="2-1-3-读取内存"><a href="#2-1-3-读取内存" class="headerlink" title="2.1.3 读取内存"></a>2.1.3 读取内存</h4><p>速度比较：内部寄存器&gt;内存</p>
<p>从内存读取数据一般要<strong>4个时间周期</strong>，而内部寄存器一般只要<strong>1个时间周期</strong></p>
<p>所以需要高速存储器辅助</p>
<p>高速存储器cache</p>
<p>一级cache在CPU</p>
<p>二级cache通过<strong>高速数据总线</strong>与CPU相联</p>
<p>cache是SRAM，即固态</p>
<h4 id="2-1-4-加载并执行程序"><a href="#2-1-4-加载并执行程序" class="headerlink" title="2.1.4 加载并执行程序"></a>2.1.4 加载并执行程序</h4><p>程序执行前，需要<strong>一种工具程序</strong>将其<strong>加载到内存</strong></p>
<p>即<strong>程序加载器</strong></p>
<p>认为解释不详细？？？</p>
<h3 id="2-2-32位x86"><a href="#2-2-32位x86" class="headerlink" title="2.2 32位x86"></a>2.2 32位x86</h3><h4 id="2-2-1-操作系统"><a href="#2-2-1-操作系统" class="headerlink" title="2.2.1 操作系统"></a>2.2.1 操作系统</h4><h4 id="2-2-2-基本执行环境"><a href="#2-2-2-基本执行环境" class="headerlink" title="2.2.2 基本执行环境"></a>2.2.2 基本执行环境</h4><p><strong>寄存器</strong>直接位于CPU内的高速存储位置</p>
<p>来自知乎的形象比喻</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">如果把被储存的东西比作能量：</span><br><span class="line">1. 寄存器就是 ATP，可以随时拿来用，性能高，但数量有限；</span><br><span class="line">2. 内存就是葡萄糖，性能一般，但是存量可以比较多；</span><br><span class="line">3. 外存（比如硬盘）就是脂肪，容量可以非常大，性能很差，要先转化为葡萄糖（存进内存），然后转化为 ATP（放到寄存器）才能直接利用（存取）。</span><br><span class="line"></span><br><span class="line">作者：Pluveto</span><br><span class="line">链接：https://www.zhihu.com/question/20539463/answer/724173258</span><br><span class="line">来源：知乎</span><br><span class="line">著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。</span><br></pre></td></tr></table></figure>

<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">寄存器的功能是存储二进制代码，它是由具有存储功能的触发器组合起来构成的。一个触发器可以存储1位二进制代码，故存放n位二进制代码的寄存器，需用n个触发器来构成</span><br></pre></td></tr></table></figure>

<p><a target="_blank" rel="noopener external nofollow noreferrer" href="https://baike.baidu.com/item/%E5%AF%84%E5%AD%98%E5%99%A8/187682?fr=aladdin">百度百科</a></p>
<h5 id="基本程序执行寄存器"><a href="#基本程序执行寄存器" class="headerlink" title="基本程序执行寄存器"></a>基本程序执行寄存器</h5><h5 id="通用寄存器"><a href="#通用寄存器" class="headerlink" title="通用寄存器"></a>通用寄存器</h5><p>用于<strong>算数运算</strong>和<strong>数据传输</strong></p>
<p>AH(8位)+AL（8位）&#x3D;AX（16位）</p>
<p>EAX(32位)</p>
<p>●乘除指令默认使用EAX。它常常被称为扩展累加器(extended accumulator)寄存器。<br>●CPU默认使用ECX为循环计数器<br>●ESP用于寻址堆栈(一种系统内存结构)数据。它极少用于一般算术运算和数据传输，通常被称为<strong>扩展堆栈指针</strong>(extended stack pointer)寄存器<br>●ESI和EDI用于高速存储器传输指令，有时也被称为<strong>扩展源变址</strong>(extended souree index)寄存器和<strong>扩展目的变址</strong>(extended destination index)寄存器</p>
<p>●高级语言通过EBP来引用堆栈中的函数参数和局部变量。除了高级编程，它不用于一般算术运算和数据传输。它常常被称为扩展帧指针(extended frame pointer)寄存器</p>
<h5 id="段寄存器"><a href="#段寄存器" class="headerlink" title="段寄存器"></a>段寄存器</h5><p>存放<strong>预先分配的内存区域</strong>的基址，这些内存区域就是<strong>段</strong></p>
<p>实地址模式中， 16 位段寄存器表示的是预先分配的内存区域的基址，这个内存区域称为段。保护模式中，段寄存器中存放的是段描述符表指针。一些段中存放<strong>程序指令</strong>(代码).其他段<strong>存放变量</strong>(数据),还有一个堆栈段存放的是<strong>局部函数变量和函数参数</strong>。</p>
<h5 id="指令指针寄存器"><a href="#指令指针寄存器" class="headerlink" title="指令指针寄存器"></a>指令指针寄存器</h5><p>存放<strong>下一条</strong>要执行指令的地址</p>
<h5 id="标志（flags）寄存器"><a href="#标志（flags）寄存器" class="headerlink" title="标志（flags）寄存器"></a>标志（flags）寄存器</h5><p>包含了独立的 二进制位，用于控制CPU的操作，或是反映一些CPU操作的结果。有些指令可以测试和控制这些单独的处理器标志位</p>
<p><strong>设置标志位时，该标识位&#x3D;1，清除（或重置）标识位时，该标志位&#x3D;0。</strong></p>
<p>包含的独立二进制位用于控制CPU操作，并反应ALU操作的结果</p>
<p>控制标志位</p>
<p>程序能够通过设置EFLAGS寄存器中的单独位来控制CPU的操作，比如，<strong>方向标志位</strong>和<strong>中断标志位</strong>。</p>
<p>状态标志位</p>
<p>●进位标志位(CF).与目标位置相比，<strong>无符号</strong>算术运算结果太大时，设置该标志位。<br>●溢出标志位(OF). 与目标位置相比，<strong>有符号</strong>算术运算结果太大或太小时，设置该标志位。</p>
<p>●符号标志位(SF), 算术或逻辑操作<strong>产生负结果</strong>时， 设置该标志位。<br>●零标志位(ZF). 算术或逻辑操作产生的结果为零时，设置该标志位。<br>●辅助进位标志位(AC), 算术操作在8位操作数中产生了位3向位4的进位时，设置该标志位。<br>●奇偶校验标志位(PF)， 结果的最低有效字节包含偶数个1时，设置该标志位，否则，清除该标志位。一般情况下， 如果数据有可能被修改或损坏时，该标志位用于进行错误检测。</p>
<h5 id="MMX寄存器"><a href="#MMX寄存器" class="headerlink" title="MMX寄存器"></a>MMX寄存器</h5><p>intel专属</p>
<h5 id="XMM-寄存器"><a href="#XMM-寄存器" class="headerlink" title="XMM 寄存器"></a>XMM 寄存器</h5><p>浮点单元</p>
<p>以上内容在P28-30</p>
<h4 id="2-2-3-x86内存管理"><a href="#2-2-3-x86内存管理" class="headerlink" title="2.2.3 x86内存管理"></a>2.2.3 x86内存管理</h4><h3 id="2-3-64位的x86-64位处理器"><a href="#2-3-64位的x86-64位处理器" class="headerlink" title="2.3 64位的x86-64位处理器"></a>2.3 64位的x86-64位处理器</h3><p>比x86多了8个通用寄存器</p>
<h3 id="2-4-典型X86计算机组件"><a href="#2-4-典型X86计算机组件" class="headerlink" title="2.4 典型X86计算机组件"></a>2.4 典型X86计算机组件</h3><h3 id="2-5-基本输入输出系统"><a href="#2-5-基本输入输出系统" class="headerlink" title="2.5 基本输入输出系统"></a>2.5 基本输入输出系统</h3><h5 id="2-5-1-I-x2F-O访问层次"><a href="#2-5-1-I-x2F-O访问层次" class="headerlink" title="2.5.1 I&#x2F;O访问层次"></a>2.5.1 I&#x2F;O访问层次</h5><p>通用操作系统<strong>极少允许</strong>应用程序<strong>直接访问硬件</strong></p>
<h2 id="3-汇编语言基础"><a href="#3-汇编语言基础" class="headerlink" title="3 汇编语言基础"></a>3 汇编语言基础</h2><h3 id="3-1-基本语言元素"><a href="#3-1-基本语言元素" class="headerlink" title="3.1 基本语言元素"></a>3.1 基本语言元素</h3><h4 id="3-1-1-第一个汇编语言程序"><a href="#3-1-1-第一个汇编语言程序" class="headerlink" title="3.1.1 第一个汇编语言程序"></a>3.1.1 第一个汇编语言程序</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">sum dword 0</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov eax,5</span><br><span class="line">	add eax,6</span><br><span class="line">	moc sum,eax</span><br><span class="line"></span><br><span class="line">	INVOKE ExitProcess,0</span><br><span class="line">main ENDP</span><br></pre></td></tr></table></figure>



<p>这个示范不可运行</p>
<p>变量sum申明大小为32为，关键字是dword</p>
<p>.code .data 为段，后面还要命名一种段，是<strong>堆栈</strong></p>
<p>分号开头为注释</p>
<p><strong>需要借助调试器运行</strong>（初期没有调试器什么都干不了）</p>
<h4 id="3-1-2-整数常量"><a href="#3-1-2-整数常量" class="headerlink" title="3.1.2 整数常量"></a>3.1.2 整数常量</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">26d ;十进制</span><br><span class="line">11010011b ;二进制</span><br><span class="line">42o ;八进制</span><br><span class="line">1Ah</span><br><span class="line">0A3h ；十六进制</span><br></pre></td></tr></table></figure>



<h4 id="3-1-3-整数常量表达式"><a href="#3-1-3-整数常量表达式" class="headerlink" title="3.1.3 整数常量表达式"></a>3.1.3 整数常量表达式</h4><p>是一种算数表达式，包含整数常量和算数运算符</p>
<h4 id="3-1-4-实数常量"><a href="#3-1-4-实数常量" class="headerlink" title="3.1.4 实数常量"></a>3.1.4 实数常量</h4><p>至少需要一个数字和一个十进制小数点</p>
<p><strong>编码实数</strong>表示的是十六进制实数 </p>
<p>IEEE浮点数格式表示短实数，暂时用不到，也没讲清楚</p>
<h4 id="3-1-5-字符常量"><a href="#3-1-5-字符常量" class="headerlink" title="3.1.5 字符常量"></a>3.1.5 字符常量</h4><p>汇编器在内存中以二进制ASCII形式存储字符常量</p>
<h4 id="3-1-6-字符串常量"><a href="#3-1-6-字符串常量" class="headerlink" title="3.1.6 字符串常量"></a>3.1.6 字符串常量</h4><p>在内存中的保存形式为<strong>整数字节数值序列</strong></p>
<p>还是ASCII形式存储</p>
<h4 id="3-1-7-保留字"><a href="#3-1-7-保留字" class="headerlink" title="3.1.7 保留字"></a>3.1.7 保留字</h4><p>无大小写区分（好耶!）</p>
<h4 id="3-1-8-标识符"><a href="#3-1-8-标识符" class="headerlink" title="3.1.8 标识符"></a>3.1.8 标识符</h4><p>由程序员自行选择，<strong>用于表示变量，常数，子程序和代码标签</strong></p>
<p>（类似但本质完全不同于C语言的自定义变量）</p>
<h4 id="3-1-9-伪指令"><a href="#3-1-9-伪指令" class="headerlink" title="3.1.9 伪指令"></a>3.1.9 伪指令</h4><p>嵌入<strong>源代码</strong>中的命令，由<strong>汇编器</strong>识别和执行，不在运行时执行</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">myvar dword 26  这是伪指令</span><br><span class="line">mov eax,myvar 这是指令</span><br></pre></td></tr></table></figure>

<p><strong>定义段</strong></p>
<p>.stack 定义运行时的堆栈，并设置大小</p>
<h4 id="3-1-10-指令"><a href="#3-1-10-指令" class="headerlink" title="3.1.10 指令"></a>3.1.10 指令</h4><p>指令是一种语句，它在程序汇编编译时变得可执行</p>
<p>汇编器将指令翻译为<strong>机器语言字节</strong>（区别于伪指令）</p>
<h5 id="1-标号"><a href="#1-标号" class="headerlink" title="1.标号"></a>1.标号</h5><p>指一种标识符，是<strong>指令和数据位置的标记</strong></p>
<p><strong>数据标号</strong></p>
<p>位于指令的前端，表示指令的地址</p>
<p>位于变量的前端，表示变量的地址（确实如此，应为没有变量名）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">count dword 100</span><br><span class="line">标号  数据定义类型（指令？）  变量</span><br></pre></td></tr></table></figure>

<p><strong>代码标号</strong></p>
<p>就举下面这个例子</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">target:</span><br><span class="line">	mov ax,bx ;寄存器间是可以互相移动的</span><br><span class="line">	jmp target</span><br></pre></td></tr></table></figure>





<h5 id="2-指令助记符"><a href="#2-指令助记符" class="headerlink" title="2.指令助记符"></a>2.指令助记符</h5><p>英文是用来帮助记忆的，指令本质应当是二进制（？）</p>
<h5 id="3-操作数"><a href="#3-操作数" class="headerlink" title="3.操作数"></a>3.操作数</h5><p>（应该是翻译的锅，operation是操作，操作数不是数）</p>
<p>操作数可以是<strong>寄存器，内存操作数，整数表达式和输入输出端口</strong>（统称操作数）</p>
<p>有多个操作数时，第一个操作数为<strong>目的操作数</strong>，第二个操作数为<strong>源操作数</strong></p>
<p>一般情况下<strong>目的操作数</strong>的内容由<strong>指令修改</strong></p>
<p>stc 指令没有操作数（进位标志位置1）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">stc</span><br></pre></td></tr></table></figure>



<p>inc 指令只有一个操作数</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">inc eax ;EAX加1</span><br></pre></td></tr></table></figure>



<p>imul有3个操作数</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">imul eax，ebx,5 ;ebx与5相乘，结果存放在eax</span><br></pre></td></tr></table></figure>



<p>eax 为寄存器</p>
<p>count 为内存</p>
<h5 id="4-注释"><a href="#4-注释" class="headerlink" title="4.注释"></a>4.注释</h5><p>单行注释，使用<strong>分号</strong>；</p>
<p>块注释，使用comment伪指令定义符号实现</p>
<h5 id="5-NOP空操作指令"><a href="#5-NOP空操作指令" class="headerlink" title="5.NOP空操作指令"></a>5.NOP空操作指令</h5><p>占一个字节，用于对齐位置</p>
<h3 id="3-2-整数加减法"><a href="#3-2-整数加减法" class="headerlink" title="3.2 整数加减法"></a>3.2 整数加减法</h3><h4 id="3-2-1-AddTwo程序"><a href="#3-2-1-AddTwo程序" class="headerlink" title="3.2.1 AddTwo程序"></a>3.2.1 AddTwo程序</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov eax,5</span><br><span class="line">	add eax,6</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>第一行</p>
<p>.386表明这是个32位程序</p>
<p>第二行选择<strong>内存模式</strong>（flat）</p>
<p>stdcall确定了子程序的调用规范(32位Windows服务的要求)</p>
<p>第三行</p>
<p>运行时堆栈保留<strong>4096字节</strong>的存储器</p>
<p>第四行</p>
<p>exitprocess函数函数的<strong>原型</strong></p>
<p><strong>原型</strong>包括函数名，proto关键字，一个逗号</p>
<p>第4行声明了ExitProcess函数的原型，它是一个标准的Windows服务。原型包含了函数名、PROTO关键字、一个逗号，以及一个输人参数列表。ExitProcess 的输入参数名称为dwExitCode。可以将其看作为给Windows操作系统的返回值，返回值为零，则表示程序执行成功;而任何其他的整数值都表示了一个错误代码。因此，程序员可以将自己的汇编程序看作是被操作系统调用的子程序或过程。当程序准备结束时，它就调用ExitProcess,并向操作系统<strong>返回一个整数（!）</strong>以表示该程序运行良好。</p>
<p>最后一行</p>
<p>end伪指令标记了程序的入口（main）。标号main在前一行进行了声明，它标记了程序开始执行的地址。</p>
<h5 id="汇编伪指令回顾"><a href="#汇编伪指令回顾" class="headerlink" title="汇编伪指令回顾"></a>汇编伪指令回顾</h5><p>.stack 4096</p>
<p>4096字节是一个内存页的大小<br>数值4096可能比将要用的字节数多，但是对处理器的内存管理而言，它正好对应了一个内存页的大小。所有的现代程序在调用子程序时都会用到堆栈——首先， 用来<strong>保存传递的参数</strong>;其次，用来<strong>保存调用函数的代码的地址</strong>。函数调用结束后，CPU利用这个地址返回到函数被调用的程序点。此外，运行时堆栈还可以<strong>保存局部变量</strong>，也就是，在函数内定义的变量。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">main endp</span><br></pre></td></tr></table></figure>

<p>标记<strong>进程</strong>结束</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>表示<strong>程序</strong>结束</p>
<p>END后面可以放代码注释，代码副本</p>
<h4 id="3-2-2-运行和调试AddTwo"><a href="#3-2-2-运行和调试AddTwo" class="headerlink" title="3.2.2 运行和调试AddTwo"></a>3.2.2 运行和调试AddTwo</h4><p>调出registers，可以看到很多信息</p>
<p>右键flag，可以看到<strong>标志位信息</strong></p>
<p>0是清除，1是置位，有修改就会变红</p>
<p>便于理解程序运行</p>
<h4 id="3-2-3-程序模板"><a href="#3-2-3-程序模板" class="headerlink" title="3.2.3 程序模板"></a>3.2.3 程序模板</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">	;这里声明变量</span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	;这里编写代码</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p><strong>使用注释</strong>   在注释中包括程序说明、 程序作者的名字、创建日期，以及后续修改信息，是一个非常好的主意。这种文档对任何阅读程序清单的人(包括程序员自己，几个月或几年之后)都是有帮助的。许多程序员已经发现了，程序编写几年后，他们必须先重新熟悉自己的代码才能进行修改。如果读者正在上编程课，那么老师可能会坚持要求使用这些附加信息。</p>
<h3 id="3-3-汇编，链接和运行程序"><a href="#3-3-汇编，链接和运行程序" class="headerlink" title="3.3 汇编，链接和运行程序"></a>3.3 汇编，链接和运行程序</h3><h4 id="3-3-1-汇编-链接-执行周期"><a href="#3-3-1-汇编-链接-执行周期" class="headerlink" title="3.3.1 汇编-链接-执行周期"></a>3.3.1 汇编-链接-执行周期</h4><p>汇编语言和C语言一样，也需要链接</p>
<h4 id="3-3-2-列表文件"><a href="#3-3-2-列表文件" class="headerlink" title="3.3.2 列表文件"></a>3.3.2 列表文件</h4><p><strong>列表文件里有符号表</strong></p>
<p>若想告诉 Visual Studio生成列表文件，则在打开项目时按下述步骤操作:在Project菜单中选择Properties,在Configuration Properties 下，选择Microsoft Macro Assembler。然后选择ListingFile。在对话框中，设置Generate Preprocessed Source Listing为Yes,设置List All Avilable Information为Yes</p>
<p>(选项打开以后，VS2019就没法调试程序了)</p>
<p>表现了源文件和源文件生成的机器代码，可检查程序是否正常生成机器代码</p>
<p>数值B8 被称为<strong>操作代码</strong>，表示特定的机器指令</p>
<h3 id="3-4-定义数据"><a href="#3-4-定义数据" class="headerlink" title="3.4 定义数据"></a>3.4 定义数据</h3><h4 id="3-4-1-内部数据类型"><a href="#3-4-1-内部数据类型" class="headerlink" title="3.4.1 内部数据类型"></a>3.4.1 内部数据类型</h4><p>汇编器识别一组基本的内<strong>部数据类型</strong>,按照数据大小(字节、字、双字等等)、是否有符号、是整数还是实数来描述其类型。这些类型有相当程度的重叠——例如，<strong>DWORD类型</strong>(32位，无符号整数)就可以SDWORD类型(32位，有符号整数)相互交换。可能有人会说，程序员用SDWORD告诉读程序的人，这个值是有符号的，但是，对于汇编器来说这不是强制性的。汇编器只评估操作数的大小。因此，举例来说，程序员只能将32位整数指定为DWORD、SDWORD或者REAL4类型。表3-2给出了全部内部数据类型的列表，有些表项中的IEEE符号指的是IEEE计算机学会出版的标准实数格式。</p>
<p><img src="D:\Note\微信图片_20201011230711.jpg" alt="微信图片_20201011230711"></p>
<h4 id="3-4-2-数据定义语句"><a href="#3-4-2-数据定义语句" class="headerlink" title="3.4.2 数据定义语句"></a>3.4.2 数据定义语句</h4><p><strong>数据定义语句</strong>：在内存为变量留出存储空间，并赋予一个可选的名字</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">count dword 12345</span><br></pre></td></tr></table></figure>

<p>名字 遵守标识符规定即可</p>
<p>伪指令 上述指令外，还有DB，DW，DD，DQ，DT</p>
<p>初始值 数据定义至少要有一个初始值，即使该值为0</p>
<h4 id="3-4-3-向AddTwo程序添加一个变量"><a href="#3-4-3-向AddTwo程序添加一个变量" class="headerlink" title="3.4.3 向AddTwo程序添加一个变量"></a>3.4.3 向AddTwo程序添加一个变量</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">sum DWORD 0</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov eax,5</span><br><span class="line">	add eax,6</span><br><span class="line">	mov sum,eax</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h4 id="3-4-4-定义BYTE和SBYTE数据"><a href="#3-4-4-定义BYTE和SBYTE数据" class="headerlink" title="3.4.4 定义BYTE和SBYTE数据"></a>3.4.4 定义BYTE和SBYTE数据</h4><p>byte 定义字节</p>
<p>sbyte 定义有符号字节</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">value6 byte ?</span><br></pre></td></tr></table></figure>

<p>？表示未初始化，意味着运行时分配数值到该变量</p>
<p>可选名字是一个标号，标识从变量包含段的开始到该变量的偏移量。比如，如果 value1在数据段偏移量为0000处，并在内存中占一个字节，则value2就自动处于偏移量为0001处</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">value2 BYTE 20h</span><br><span class="line">value1 BYTE 10h</span><br></pre></td></tr></table></figure>

<p>DB伪指令也可以定义有符号或无符号的8位变量:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">val1 DB 255</span><br><span class="line">val2 DB -128</span><br></pre></td></tr></table></figure>



<h5 id="1-多初始值"><a href="#1-多初始值" class="headerlink" title="1.多初始值"></a>1.多初始值</h5><p>（为什么有这个存在?数组吗?）</p>
<p>单个数据定义时，初始值可以使用不同的基数</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">list byte 10,20,30,40</span><br></pre></td></tr></table></figure>

<p>10的偏移量是0000，20的偏移量是0001</p>
<p>在单个数据定义中，其初始值可以使用不同的基数。字符和字符串常量也可以自由组合。在下面的例子中，listl和list2有相同的内容:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1ist1 BYTE 10.32,41h,00100010b</span><br><span class="line">1ist2 BYTE 0Ah. 20h,&quot;A&#x27;.22h</span><br></pre></td></tr></table></figure>

<p>（！是不是最后都要存成二进制的缘故？）</p>
<h5 id="2-定义字符串"><a href="#2-定义字符串" class="headerlink" title="2.定义字符串"></a>2.定义字符串</h5><p>2.定义字符串<br>定义一个字符申，要用单引号或双引号将其括起来。最常见的字符中类型是用-一个空字节(值为0)作为结束标记，称为以空字节结束的字符串，很多编程语言中都使用这种类型的字符串:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">greetingl BrtE &quot;Good afternoon&quot;.o</span><br><span class="line">grcecing2 BrTE &#x27;Good night&quot;.0</span><br></pre></td></tr></table></figure>

<p>每个字符占一个字节的存储空间。对于字节数值必须用逗号分隔的规则而言，字符申是<br>个例外。如果没有这种例外，greeting1就会被定义为:</p>
<p>每个字符占一个字节的存储空间。对于字节数值必须用逗号分隔的规则而言，字符申是个例外。如果没有这种例外，greeting1就会被定义为:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">greeting1 BYtE &#x27;o&#x27;.o&#x27;.&quot;o&#x27;.&#x27;d&#x27;....etc</span><br></pre></td></tr></table></figure>

<p>字符串可以分为多行，并且不用为每一行都添加标号:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"></span><br></pre></td></tr></table></figure>

<p>十六进制代码0Dh和0Ah也被称为CRLF(回车换行符)或行结束字符。在编写标准输出时，它们将光标移动到当前行的下一行的左侧，行连续字符()把两个源代码行连接成一条语句，它必须是一行的最后一个字符。</p>
<h5 id="3-DUP操作符"><a href="#3-DUP操作符" class="headerlink" title="3.DUP操作符"></a>3.DUP操作符</h5><p>DUP操作符使用一个整数表达式作为计数器，为多个数据项分配存储空间</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">BYTE 20 DUP(0) ;20个字节，值全部为0</span><br><span class="line">BYTE 20 DUP(?) ;20个字节，非初始化</span><br><span class="line">BYTE 4 DUP(&quot;STACK&quot;)</span><br></pre></td></tr></table></figure>



<h4 id="3-4-5-定义word和sword数据"><a href="#3-4-5-定义word和sword数据" class="headerlink" title="3.4.5 定义word和sword数据"></a>3.4.5 定义word和sword数据</h4><p>word（定义字）</p>
<p>sword（定义有符号字）</p>
<p>DD 32位整数或实数（双字）</p>
<p>是否是有无符号型，取决于数字赋值是否有负号</p>
<p><strong>16位字数组</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mylist word 1，2，3，4，5</span><br><span class="line">mylist word 5 dup(?)</span><br></pre></td></tr></table></figure>





<h4 id="3-4-6-定义dword和dsword"><a href="#3-4-6-定义dword和dsword" class="headerlink" title="3.4.6 定义dword和dsword"></a>3.4.6 定义dword和dsword</h4><p>dword（定义双字）</p>
<p>sdword（定义有符号双字）</p>
<p>dword还可以声明一种变量，这种变量包含的是另一个变量的32位偏移量</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pval dword val3</span><br></pre></td></tr></table></figure>



<p><strong>32位双字</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mylist dword 1,2,3,4,5</span><br></pre></td></tr></table></figure>



<h4 id="3-4-7-定义qword数据"><a href="#3-4-7-定义qword数据" class="headerlink" title="3.4.7 定义qword数据"></a>3.4.7 定义qword数据</h4><p>qword(定义四字)伪指令为64位数值分配空间</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">quadl qword 12345678h</span><br></pre></td></tr></table></figure>

<p>不然就是DQ</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">quadl DQ 12345678h</span><br></pre></td></tr></table></figure>



<h4 id="3-4-8-定义压缩BCD（TBYTE）数据"><a href="#3-4-8-定义压缩BCD（TBYTE）数据" class="headerlink" title="3.4.8 定义压缩BCD（TBYTE）数据"></a>3.4.8 定义压缩BCD（TBYTE）数据</h4><p>Intel把一个压缩的二进制编码的十进制(BCD，Binary Coded Decimal)整数存放在一个10字节的包中。每个字节(除了最高字节之外)包含两个十进制数字。在低9个存储字节中，每半个字节都存放了一个十进制数字。最高字节中，最高位表示该数的符号位。如果最高字节为80h，该数就是负数;如果最高字节为00h，该数就是正数。整数的范围是-999 999 999 999 999 999到 +999 999 999 999 999 999</p>
<p>示例下表列出了正、负十进制数1234的十六进制存储字节，排列顺序从最低有效字。</p>
<p>第二个例子无效的原因是MASM将常数编码为二进制整数，而不是压缩BCD整数。如果想要把一个实数编码为压缩BCD码，可以先用FLD指令将该实数加载到浮点寄存器堆栈，再用FBSTP指令将其转换为压缩BCD码，该指令会把数值舍人到最接近的整数</p>
<h4 id="3-4-9-定义浮点类型"><a href="#3-4-9-定义浮点类型" class="headerlink" title="3.4.9 定义浮点类型"></a>3.4.9 定义浮点类型</h4><p>real4定义4字节单精度浮点变量（短实数），real8定义8字节双精度浮点变量（长实数），real10定义10字节扩展精度。每个伪指令都需要一个或多个实常数初始值（扩展精度实数）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">rval real4 -1.2</span><br><span class="line">rval real8 3.2e-260</span><br></pre></td></tr></table></figure>



<h4 id="3-4-10-变量加法程序"><a href="#3-4-10-变量加法程序" class="headerlink" title="3.4.10 变量加法程序"></a>3.4.10 变量加法程序</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">firstval dword 20002000h</span><br><span class="line">secondval dword 11111111h</span><br><span class="line">thirdval dword 22222222h</span><br><span class="line">sum dword 0</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov eax,firstval</span><br><span class="line">	add eax,secondval</span><br><span class="line">	add eax,thirdval</span><br><span class="line">	mov sum,eax</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p><strong>x86指令集不允许将一个变量直接与另一个变量相加，但是允许一个变量与一个寄存器相加</strong></p>
<p>最终数是5333 5333（16进制）</p>
<h4 id="3-4-11-小端顺序"><a href="#3-4-11-小端顺序" class="headerlink" title="3.4.11 小端顺序"></a>3.4.11 小端顺序</h4><p><strong>这很重要！</strong></p>
<p>x86处理器在内存中按小端(little-endian)顺序(低到高)存放和检索数据。<strong>最低有效字节</strong>存放在分配给该数据的第一个内存地址中，剩余字节存放在随后的连续内存位置中。</p>
<p>考虑一个双字12345678h（占用4个字节）。如果将其存放在偏移量为0000的位置，**则78h存放在第一个字节(0000)，56h存放在第二个字节(0001)**，余下的字节存放地址偏移量为0002和0003</p>
<p>然而有些计算机用的是大端顺序</p>
<h4 id="3-4-12-声明未初始化数据"><a href="#3-4-12-声明未初始化数据" class="headerlink" title="3.4.12 声明未初始化数据"></a>3.4.12 声明未初始化数据</h4><p>.data ? 伪指令声明未初始化数据,减小了编译程序的大小</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">smallarray dword 10 dup(0)</span><br><span class="line">.data?</span><br><span class="line">bigarray dword 5000 dup(?)</span><br></pre></td></tr></table></figure>

<p>需要有比较，上面的节省空间（20000个字节）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">smallarray dword 10 dup(0)</span><br><span class="line">bigarray dword 5000 dup(?)</span><br></pre></td></tr></table></figure>

<p><strong>代码可以与数据混合</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">.code</span><br><span class="line">mov eax,ebx</span><br><span class="line">.data</span><br><span class="line">temp DWORD ?</span><br><span class="line">.code</span><br><span class="line">mov temp,eax</span><br></pre></td></tr></table></figure>

<p>temp打断了可执行执行流，可以但不推荐</p>
<h3 id="3-5-符号常量"><a href="#3-5-符号常量" class="headerlink" title="3.5 符号常量"></a>3.5 符号常量</h3><p>通过为整数表达式或文本指定标识符来创建符号常量(symbolic constant)(也称符号定义(symbolic definition))。符号不预留存储空间。它们只在汇编器扫描程序时使用，并且在运行时不会改变。下表总结了符号与变量之间的不同:</p>
<p>符号：<strong>不使用内存</strong>，<strong>运行时数值不改变</strong></p>
<h4 id="3-5-1-等号伪指令（包含当前地址计数器）"><a href="#3-5-1-等号伪指令（包含当前地址计数器）" class="headerlink" title="3.5.1 等号伪指令（包含当前地址计数器）"></a>3.5.1 等号伪指令（包含当前地址计数器）</h4><p>（这些东西都是放在.code里的喽？好像不一定）</p>
<p>把一个<strong>符号名</strong>称与一个<strong>整数表达式</strong>连接起来</p>
<p>整数表达式 既是</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">count = 500</span><br></pre></td></tr></table></figure>

<p>可以被重定义，即量是可以改变的！</p>
<p><strong>当前地址计数器 $</strong></p>
<p>下面的语句声明了一个变量selfPtr，并将其初始化为该变量的偏移量</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">selfPtr dword $</span><br></pre></td></tr></table></figure>



<h4 id="3-5-2-计算数组和字符串的大小"><a href="#3-5-2-计算数组和字符串的大小" class="headerlink" title="3.5.2 计算数组和字符串的大小"></a>3.5.2 计算数组和字符串的大小</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">List byte 10,20,30,40</span><br><span class="line">listsize = ($ - list)</span><br></pre></td></tr></table></figure>

<p><strong>ListSize必须紧跟在list的后面</strong>。下面的例子中，计算得到的ListSize值(24)就过大</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">list BYTE 10,20.30,40</span><br><span class="line">var2 BYTE 20 DUP(?)</span><br><span class="line">Listsize = ($ - list)</span><br></pre></td></tr></table></figure>

<p>不需要手动计算字符串的长度，让汇编器完成这个工作:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mystring BYtE &quot;This is a long string, containing&quot;</span><br><span class="line">BYTE &quot;any number of characters&quot;</span><br><span class="line">myString_len = ($ - myString)</span><br></pre></td></tr></table></figure>



<p><strong>字数组和双字数组</strong></p>
<p>字数组和双字数组当要计算元素数量的数组中包含的不是字节时，就应该用数组总的大小（按字节计）除以单个元素的大小。比如，在下例中，由于数组中的每个学要上占2个字节（16位），因此，地址范围应该除以2：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">1ist woRD 1000h，2000h，3000h，4000h</span><br><span class="line">Listsize = ($ - list)/2</span><br></pre></td></tr></table></figure>

<p>双字数组</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">DWORD 10000000h，20000000h，30000000h，40000000h</span><br><span class="line">Listsize = ($ - list)/4</span><br></pre></td></tr></table></figure>



<h4 id="3-5-3-EQU伪指令"><a href="#3-5-3-EQU伪指令" class="headerlink" title="3.5.3 EQU伪指令"></a>3.5.3 EQU伪指令</h4><p>把一个<strong>符号名</strong>称与一个<strong>整数表达式</strong>或一个<strong>任意文本</strong>连接起来</p>
<p>下面示例将一个符号和一个字符串连接起来，然后用该符号定义一个变量</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">presskey equ &lt;&quot;Prees any key&quot;,0&gt;</span><br><span class="line">.data</span><br><span class="line">prompt byte presskey</span><br></pre></td></tr></table></figure>



<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">matrix1 equ 10*10</span><br><span class="line">matrix2 equ &lt;10*10&gt;</span><br><span class="line">.data</span><br><span class="line">M1 word matrix1</span><br><span class="line">M2 word matrix2</span><br></pre></td></tr></table></figure>

<p>等价于</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">m1 word 100</span><br><span class="line">m2 word 10*10</span><br></pre></td></tr></table></figure>

<p>这东西<strong>不能重定义</strong>！</p>
<p><strong>不能重定义</strong>！</p>
<h4 id="3-5-4-TEXTQU伪指令"><a href="#3-5-4-TEXTQU伪指令" class="headerlink" title="3.5.4 TEXTQU伪指令"></a>3.5.4 TEXTQU伪指令</h4><p>TEXTEQU伪指令，类似于EQU，创建了文本宏(text macro)。它有3种格式:第一种<br>为名称分配的是文本;第二种分配的是已有文本宏的内容;第三种分配的是整数常量表达式:<br>name TEXTEQU <text></p>
<p>name TExTEQU textmacro</p>
<p>name TExTEQU $constExpr</p>
<p>例如，变量prompt1使用了文本宏 continueMsg:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">continueMsg TEXTEQU c&quot;Do you wish to continue (Y/N)?&quot;s</span><br><span class="line">.data</span><br><span class="line">promptl BYTE continueMsg</span><br></pre></td></tr></table></figure>

<p>文本宏可以相互构建。如下例所示，count被赋值了一个整数表达式，其中包含rowSize<br>然后，符号move被定义为mov。最后，用move和count创建setupAL:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">rowsize = 5</span><br><span class="line">count TEXTEQU %(rowsize*21)</span><br><span class="line">move TEXTEQU &lt;mov&gt;</span><br><span class="line">setupAL TEXTEQU &lt;move al. count&gt;</span><br></pre></td></tr></table></figure>

<p>因此，语句<br>Setupal<br>就会被汇编为<br>mov al,10</p>
<p><strong>用TEXTEQU定义的符号随时可以被重新定义</strong></p>
<h3 id="3-6-64位编程-程序模板"><a href="#3-6-64位编程-程序模板" class="headerlink" title="3.6 64位编程(程序模板)"></a>3.6 64位编程(程序模板)</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">ExitProcess PROTO</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">sum dword 0</span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov eax,5</span><br><span class="line">	mov sum,eax</span><br><span class="line"></span><br><span class="line">	mov ecx,0</span><br><span class="line">	call ExitProcess</span><br><span class="line">main ENDP</span><br><span class="line">END </span><br></pre></td></tr></table></figure>

<p>执行不了，不知道哪儿出错了</p>
<p><strong>使用64位的寄存器</strong></p>
<p>dword变为qword</p>
<p>eax变为rax</p>
<h3 id="3-7-本章小结"><a href="#3-7-本章小结" class="headerlink" title="3.7 本章小结"></a>3.7 本章小结</h3><p><strong>整型常量表达式</strong>是算术表达式，包括了整数常量。符号常量和算术运算符。优先级是指当表达式有两个或更多运算符时，运算符的隐含顺序</p>
<p><strong>字符常量</strong>是用引号括起来的单个字符。汇编器把字符转换为一个字节，其中包含的是该字符的二进制ASCI码。字符事常量是用引号括起来的字符序列，可以选择用空字节标记结束。</p>
<p><strong>汇编语言</strong>有一组保留字。它们含义特殊且只能用于正确的上下文中。标识符是程序员选择的名称。用于标识变量、符号常量、子程序和代码标号。不能用保留字作标识符</p>
<p><strong>伪指令</strong>是嵌在源代码中的命令，由汇编器进行转换。指令是源代码语句，由处理器在运行时执行。指令助记符是短关键字，用于标识指令执行的操作。标号是一种标识符，用作指令或数据的位置标记</p>
<p><strong>操作数</strong>是传递给指令的数据。一条汇编指令有0一~3个操作数，每一个都可以是寄存器、内存操作数、整数表达式成输人&#x2F;输出端口号</p>
<h2 id="4-数据传送，寻址和算数运算"><a href="#4-数据传送，寻址和算数运算" class="headerlink" title="4 数据传送，寻址和算数运算"></a>4 数据传送，寻址和算数运算</h2><p>本章介绍了数据传送和算术运算的若干必要指令，用大量的篇幅说明了基本寻址模式,如直接寻址、立即寻址和可以用于处理数组的间接寻址。同时，还展示了怎样创建循环和怎样使用一些基本运算符，如OFFSET,PTR和LENGTHOF。阅读本章后，将会了解除条件语句之外的汇编语言的基本工作知识。</p>
<h3 id="4-1-数据传送指令"><a href="#4-1-数据传送指令" class="headerlink" title="4.1 数据传送指令"></a>4.1 数据传送指令</h3><h4 id="4-1-1引言"><a href="#4-1-1引言" class="headerlink" title="4.1.1引言"></a>4.1.1引言</h4><p>用Java或C++这样的语言编程时，编译器产生的大量语法错误信息很容易让初学者感到心烦。编译器执行严格类型检查，以避免可能出现诸如不匹配变量和数据的错误。另一方面，只要处理器指令集允许，汇编器就能完成任何操作请求。换句话说，汇编语言就是将程序员的注意力集中在数据存储和具体机器细节上。编写汇编语言代码时，必须要了解处理器的限制。而x86处理器具有众所周知的复杂指令集(complex instruction set)，因此，可以用许多方法来完成任务如果花时间深入了解本章介绍的材料，则阅读本书其他内容会更加顺利。随着示例程序越来越复杂，需要依赖对本章介绍的基础工具的掌握。</p>
<h4 id="4-1-2-操作数类型"><a href="#4-1-2-操作数类型" class="headerlink" title="4.1.2 操作数类型"></a>4.1.2 操作数类型</h4><p>指令包含的操作数个数可以是:0个，1个，2个或3个。这里，为了清晰起见，省略掉标号和注释:<br>meronic<br>mnemonic ldestinationl<br>mnemonic Idestinaclon],[sourcel<br>mnemonic [destination],[source-l],[tsource-2]</p>
<p>操作数有3种基本类型:<br>●立即数——使用数字文本表达式<br>●寄存器操作数——使用CPU内已命名的寄存器<br>●内存操作数——引用内存位置</p>
<p>这些符号来自intel手册</p>
<p>AH+AL&#x3D;AX</p>
<h4 id="4-1-3-直接内存操作数"><a href="#4-1-3-直接内存操作数" class="headerlink" title="4.1.3 直接内存操作数"></a>4.1.3 直接内存操作数</h4><p>变量名引用的是数据段内的偏移量。例如，如下变量varl的声明表示，该变量的大小类型为字节，值为十六进制的10:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">varl BYTE 10h</span><br></pre></td></tr></table></figure>

<p>可以编写指令，通过内存操作数的地址来解析(查找)这些操作数。假设varl的地址偏移量为10400h。如下指令将该变量的值复制到AL寄存器中:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mov a1 varl</span><br></pre></td></tr></table></figure>

<p>指令会被汇编为下面的机器指令:<br>A0 00010400</p>
<p>这条机器指令的第一个字节是操作代码(即操作码(opcode))。剩余部分是var1的32位十六进制地址。虽然编程时有可能只使用数字地址，但是如同var1一样的符号标号会让使用内存更加容易。</p>
<h4 id="4-1-4-MOV指令"><a href="#4-1-4-MOV指令" class="headerlink" title="4.1.4 MOV指令"></a>4.1.4 MOV指令</h4><p>左边操作数是目标操作数，右边操作数是源操作数</p>
<p>。两个操作数必须是同样的大小<br>。两个操作数不能同时为内存操作数<br>。指令指针寄存器(IP、EIP或RIP)不能作为目标操作数</p>
<h5 id="内存到内存"><a href="#内存到内存" class="headerlink" title="内存到内存"></a><strong>内存到内存</strong></h5><p>单条MOV指令不能用于直接将数据从一个内存位置传送到另一个内存位置。相反，在将源操作数的值赋给内存操作数之前，<strong>必须先将该数值传送给一个寄存器</strong></p>
<p>书本示例无法直接运行</p>
<h5 id="覆盖值"><a href="#覆盖值" class="headerlink" title="覆盖值"></a>覆盖值</h5><p>下述代码示例演示了怎样通过使用不同大小的数据来修改同一个32位寄存器。当oneWord字传送到AX时，它就覆盖了AL中已有的值。当oneDword传送到EAX时，它就覆盖了AX的值。最后。当0被传送到AX时，它就覆盖了EAX的低半部分。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">onebyte byte 78h</span><br><span class="line">oneword word 1234h</span><br><span class="line">onedword dword 12345678h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov eax,0</span><br><span class="line">	mov al,onebyte</span><br><span class="line">	mov ax,oneword</span><br><span class="line">	mov eax,onedword</span><br><span class="line">	mov ax,0</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>就是al管低2 byte（8位），ax管低4 byte（16位），eax管8 byte（32位）</p>
<h4 id="4-1-5-整数的全零-x2F-符号扩展"><a href="#4-1-5-整数的全零-x2F-符号扩展" class="headerlink" title="4.1.5 整数的全零&#x2F;符号扩展"></a>4.1.5 整数的全零&#x2F;符号扩展</h4><h5 id="1-把一个较小的值复制到一个较大的操作数"><a href="#1-把一个较小的值复制到一个较大的操作数" class="headerlink" title="1.把一个较小的值复制到一个较大的操作数"></a>1.把一个较小的值复制到一个较大的操作数</h5><p>尽管MOV指令不能直接将较小的操作数复制到较大的操作数中。但是程序员可以想办法解决这个问题。假设要将count(无符号，16位)传送到ECX(32位)。可以先将ECX设置为0，然后将count传送到CX:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">count WORD 1</span><br><span class="line">.code</span><br><span class="line">mov ecx,0</span><br><span class="line">nov cx,count</span><br></pre></td></tr></table></figure>

<p>如果对一个有符号整数-16进行同样的操作会发生什么呢?</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">signedval swORD -16</span><br><span class="line">.code</span><br><span class="line">mov ecx,0</span><br><span class="line">nov cx,oignedVal</span><br></pre></td></tr></table></figure>



<p>ECX中的值(+65520)与-16完全不同。但是，如果先将ECX设置为FFFFFFh,然后再把signedVal复制到CX，那么最后的值就是完全正确的:</p>
<p>(见书本)</p>
<p>本例的有效结果是用源操作数的最高位(1)来填充目的操作数ECX的高16位，这种技术称为符号扩展(signextension)。当然，不能总是假设源操作数的最高位是1，幸证的是。Intel的工程师在设计指令集时已经预见到了这个问题，因此，设置了MOVZX和MOVSX指令来分别处理无符号整数和有符号整数。</p>
<h5 id="2-MOVZX-指令"><a href="#2-MOVZX-指令" class="headerlink" title="2.MOVZX 指令"></a>2.MOVZX 指令</h5><p>MOVZX(进行全零扩展并传送)（zero ex），将源操作数复制到目的操作数，并把目的操作数0扩展到16位或32位。该指令只用于<strong>无符号整数</strong></p>
<h5 id="3-MOVSX-指令"><a href="#3-MOVSX-指令" class="headerlink" title="3.MOVSX 指令"></a>3.MOVSX 指令</h5><p>MOVSX（进行符号扩展并传送）</p>
<p>如果一个十六进制常数的最大有效数字大于7，那么它的最高位等于1。如下例所示,传送到BX的十六进制数值为A69B，因此，数字“A”就意味着最高位是1。(<strong>A69B前面的0是一种方便的表示法，用于防止汇编器将常数误认为标识符</strong>)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mov bx,0A69Bh</span><br><span class="line">movsx eax,bx    ;EAX=FFFFA69Bh</span><br><span class="line">movsx eDx,bl    ;EDX=FFFFFF9Bh</span><br><span class="line">movsx cx,bl     ;CX=GG9Bh</span><br></pre></td></tr></table></figure>



<h4 id="4-1-6-LAHF和SAHF指令"><a href="#4-1-6-LAHF和SAHF指令" class="headerlink" title="4.1.6 LAHF和SAHF指令"></a>4.1.6 LAHF和SAHF指令</h4><p>LAHF(加载状态标志位到AH)指令将EFLAG寄存器的低字节复制到AH。被复制</p>
<h4 id="4-1-7-XCHG指令"><a href="#4-1-7-XCHG指令" class="headerlink" title="4.1.7 XCHG指令"></a>4.1.7 XCHG指令</h4><p>XCHG（交换数据）指令交换两个操作数的内容</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">xchg var1,bx  ;交换16位内存操作数与BX寄存器的内容</span><br></pre></td></tr></table></figure>

<p>如果要交换两个内存操作数，需要用寄存器作为临时容器</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mov ax,bx</span><br><span class="line">xchg ax,val2</span><br><span class="line">mov vall,ax</span><br></pre></td></tr></table></figure>



<h4 id="4-1-8-直接-偏移量操作数"><a href="#4-1-8-直接-偏移量操作数" class="headerlink" title="4.1.8 直接-偏移量操作数"></a>4.1.8 直接-偏移量操作数</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">arrayb byte 10h,20h,30h,40h,50h</span><br><span class="line">mov a1,arrayB</span><br><span class="line">mov al,[arrayB+1]</span><br></pre></td></tr></table></figure>

<p>以下属于事件案例</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">arrayb byte 10h,20h,30h,40h,50h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov al,arrayB</span><br><span class="line">mov ah,[arrayB+1]</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>eax的显示就是2010h</p>
<p>形如arrayB+1一样的表达式通过在变量偏移量上加常数来形成所谓的有效地址。有效地址外面的括号表明，通过解析这个表达式就可以得到该内存地址指示的内容。汇编器并不要求在地址表达式之外加括号，但为了清晰明了，本书还是强烈建议使用括号。<br>MASM没有内置的有效地址范围检查。在下面的例子中，假设数组arrayB有5个字节,面指令访问的是该数组范围之外的一个内存字节。其结果是一种难以发现的逻辑错误，因此，在检查数组引用时要非常小心</p>
<p><strong>字和双字数组</strong>在16位的字数组中，每个数组元素的偏移量比前一个多2个字节。这就是为什么在下面的例子中，数组ArrayW加2才能指向该数组的第二个元素:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">arrayw word 100h,200h,300h</span><br><span class="line">.code</span><br><span class="line">mov ax,arrayw ;AX = 100h</span><br><span class="line">mov ax,[arrayW+2] ;AX=200h</span><br></pre></td></tr></table></figure>

<p>同样，如果是双字数组，则第一个元素偏移量加4才能指向第二个元素</p>
<h4 id="4-1-9-示例程序（Moves）"><a href="#4-1-9-示例程序（Moves）" class="headerlink" title="4.1.9 示例程序（Moves）"></a>4.1.9 示例程序（Moves）</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">val1 word 1000h</span><br><span class="line">val2 word 2000h</span><br><span class="line">arrayb byte 10h,20h,30h,40h,50h</span><br><span class="line">arrayw word 100h,200h,300h</span><br><span class="line">arrayd dword 10000h,20000h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">;演示movzx指令</span><br><span class="line">mov bx,0A69Bh</span><br><span class="line">movzx eax,bx</span><br><span class="line">movzx edx,bl</span><br><span class="line">movzx cx,bl</span><br><span class="line"></span><br><span class="line">;演示movsx指令</span><br><span class="line">mov bx,0A69Bh</span><br><span class="line">movsx eax,bx</span><br><span class="line">movsx edx,bl</span><br><span class="line">mov bl,7Bh</span><br><span class="line">movsx cx,bl</span><br><span class="line"></span><br><span class="line">;内存-内存的交换</span><br><span class="line">mov ax,val1</span><br><span class="line">xchg ax,val2</span><br><span class="line">mov val1,ax</span><br><span class="line"></span><br><span class="line">;直接-偏移量寻址（字节数组）</span><br><span class="line">mov al,arrayB</span><br><span class="line">mov al,[arrayB+1]</span><br><span class="line">mov al,[arrayB+2]</span><br><span class="line"></span><br><span class="line">;直接-偏移量寻址（字数组）</span><br><span class="line">mov ax,arrayW</span><br><span class="line">mov ax,[arrayW+2]</span><br><span class="line"></span><br><span class="line">;直接-偏移量寻址（双字数组）</span><br><span class="line">mov eax,arrayD</span><br><span class="line">mov eax,[arrayD+4]</span><br><span class="line">mov eax,[arrayD+4]</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>0是清除，1是置位，有修改就会变红</p>
<h3 id="4-2-加法和减法"><a href="#4-2-加法和减法" class="headerlink" title="4.2 加法和减法"></a>4.2 加法和减法</h3><p>乘法和除法在第7章，浮点运算在第12章</p>
<h4 id="4-2-1-INC和DEC"><a href="#4-2-1-INC和DEC" class="headerlink" title="4.2.1 INC和DEC"></a>4.2.1 INC和DEC</h4><p>inc(increase)和dex(decrease)指令分别表示<strong>寄存器或内存</strong>操作数<strong>加1</strong>和<strong>减一</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">myword word 1000h</span><br><span class="line">.code</span><br><span class="line">inc myword</span><br><span class="line">mov bx,myword</span><br><span class="line">dec bx</span><br></pre></td></tr></table></figure>





<h4 id="4-2-2-add指令"><a href="#4-2-2-add指令" class="headerlink" title="4.2.2 add指令"></a>4.2.2 add指令</h4><p>add指令将长度<strong>相同的</strong>源操作数和目的操作数进行<strong>相加操作</strong></p>
<p><strong>标志位</strong>会变化</p>
<h4 id="4-2-3-sub指令"><a href="#4-2-3-sub指令" class="headerlink" title="4.2.3 sub指令"></a>4.2.3 sub指令</h4><p>add指令将长度<strong>相同的</strong>源操作数和目的操作数进行<strong>相剪操作</strong></p>
<p><strong>标志位</strong>会变化</p>
<h4 id="4-2-4-NEG指令"><a href="#4-2-4-NEG指令" class="headerlink" title="4.2.4 NEG指令"></a>4.2.4 NEG指令</h4><p>neg（非）指令通过把操作数转换为其二进制补码，将操作数符号取反</p>
<p>将目标操按位取反再加1，就可以的到这个数的二进制补码</p>
<p><strong>标志位</strong>会变化</p>
<h4 id="4-2-5-执行算术表达式"><a href="#4-2-5-执行算术表达式" class="headerlink" title="4.2.5 执行算术表达式"></a>4.2.5 执行算术表达式</h4><p>Rval &#x3D; -Xval + (Yval - Zval)</p>
<p>等价于</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">Rval sdword ?</span><br><span class="line">Xval sdword 26</span><br><span class="line">Yval sdword 30</span><br><span class="line">ZVal sdword 40</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov eax,Xval</span><br><span class="line">neg eax</span><br><span class="line"></span><br><span class="line">mov ebx,Yval</span><br><span class="line">sub ebx,Zval</span><br><span class="line"></span><br><span class="line">add eax,ebx</span><br><span class="line">mov Rval,eax</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>计算器调成Dword才能显示负数</p>
<h4 id="4-2-6-加减法影响的标志位（！）"><a href="#4-2-6-加减法影响的标志位（！）" class="headerlink" title="4.2.6 加减法影响的标志位（！）"></a>4.2.6 加减法影响的标志位（！）</h4><p>执行算数运算指令时，常常想要了解结果。它是负数，正数还是零对目的操作数来说，它是太大，还是太小?这些问题的答案有助于发现计算错误，否则可能会导致程序的错误行为。检查算术运算结果使用的是CPU状态标志位的值，同时，这些值还可以触发条件分支指令，即基本的程序逻辑工具。下面是对状态标志位的简要概述:</p>
<p>●进位(CY)标志位意味着<strong>无符号整数</strong>溢出。比如，如果指令目的操作数为8位，而指令产生的结果大于二进制的111111，那么进位标志位置1。<br>●溢出(OV)标志位意味着<strong>有符号整数</strong>溢出。比如，指令目的操作数为16位，但其产生的负数结果小于十进制的-32768，那么溢出标志位置1。</p>
<p>●零标志位(ZR)意味着<strong>操作结果为0</strong>。比如，如果两个值相等的操作数相减，则零标志位置1。<br>●符号标志位(PL)意味着操作<strong>产生的结果为负数</strong>。如果目的操作数的最高有效位(MSB)置1，则符号标志位置1</p>
<p>●奇偶标志位(PE)是指，在一条算术或布尔运算指令执行后，立即判断目的操作数最低有效字节中1的个数<strong>是否为偶数</strong>。</p>
<p>●辅助进位标志位置1，意味着目的操作数最低有效字节中位3有进位。要在调试时显示CPU状态标志位，打开Register窗口，右键点击该窗口，并选择Flags。</p>
<p>OV 溢出    UP 方向   EI中断 PL符号 ZR 零  AC 辅助进位</p>
<p>PE 奇偶性 CY 进位</p>
<p>eip寄存器存储着我们cpu要读取指令的地址，没有了它，cpu就无法读取下面的指令（通俗点讲cpu就无法执行。每次相应汇编指令执行完相应的eip值就会增加)</p>
<h5 id="1-无符号数运算-零标志位、进位标志位和辅助进位标志位"><a href="#1-无符号数运算-零标志位、进位标志位和辅助进位标志位" class="headerlink" title="1.无符号数运算:零标志位、进位标志位和辅助进位标志位"></a><strong>1.无符号数运算:零标志位、进位标志位和辅助进位标志位</strong></h5><p><strong>加法和进位标志位</strong></p>
<p>加法和进位标志位如果将加法和减法分开考虑，那么进位标志位的操作是最容易解释的。两个无符号整数相加时，进位标志位是目的操作数最高有效位进位的副本。直观地说,如果和数超过了目的操作数的存储大小，就可以认为CF&#x3D;1。在下面的例子里，ADD指令将进位标志位置1，原因是，相加的和数(100h)超过了AL的大小</p>
<p>图4-3演示了在0FFh上加1时，操作数的位是如何变化的。AL最高有效位的进位复制到进位标志位。</p>
<p>另一方面，如果AX的值为00FFh，则对其进行加1操作后，和数不会超过16位，那么进位标志位清0</p>
<p>但是，如果AX的值为FFFFh，<strong>则对其进行加1操作后</strong>，AX的高位就会产生进位</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov ax,0FFFFH</span><br><span class="line">add ax,1 ;AX=0000</span><br></pre></td></tr></table></figure>



<p><strong>减法和进位标志位</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov al,1</span><br><span class="line">sub al,2</span><br></pre></td></tr></table></figure>

<p>0001变为FFFF，ac标志位变为1</p>
<p><strong>INC和DEC不会影响进位标志位，在非零操作数上NEG指令总是会将进位标志位置1</strong></p>
<p><strong>辅助进位标志位</strong></p>
<p>辅助进位AC</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov al,oFh</span><br><span class="line">add al,1   ;AC=1</span><br></pre></td></tr></table></figure>

<p>最后一个十六进制位进位了</p>
<p><strong>奇偶标志位</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mov al,10001100b</span><br><span class="line">add al,00000010b   ;PF(PE Flag)=1</span><br><span class="line">sub al,10000000b   ;PE=0</span><br></pre></td></tr></table></figure>



<h5 id="2-有符号运算：符号标志位和溢出标志位"><a href="#2-有符号运算：符号标志位和溢出标志位" class="headerlink" title="2.有符号运算：符号标志位和溢出标志位"></a>2.有符号运算：符号标志位和溢出标志位</h5><p><strong>符号标志位</strong></p>
<p>有符号数算数操作结果为负数，则符号标志位置1</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov eax,4</span><br><span class="line">sub eax,5  ;PL标志位变为1</span><br></pre></td></tr></table></figure>



<p><strong>溢出标志位</strong></p>
<p>有符号数算数操作结果与目的操作数相比，如果发生上溢或下溢，则溢出标志位为1</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov al,+127</span><br><span class="line">add al,1  ;OV标志位变为1</span><br></pre></td></tr></table></figure>



<p><strong>加法测试</strong></p>
<p>两个正数相加，结果为负数</p>
<p>两个负数相加，结果为正数</p>
<p>两个加数的符号相反，<strong>则不可能发生溢出</strong></p>
<p>NEG<strong>指令</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov al,-128</span><br><span class="line">neg al  ;EAX没有变，CY标志位变为1</span><br></pre></td></tr></table></figure>

<p>AL储存不了有符号的正128，AL的值不会改变，AL的值置为1</p>
<p><strong>CPU不知道一个算数运算符是有符号的还是无符号的</strong></p>
<h4 id="4-2-7-示例程序（AddSubTest）"><a href="#4-2-7-示例程序（AddSubTest）" class="headerlink" title="4.2.7 示例程序（AddSubTest）"></a>4.2.7 示例程序（AddSubTest）</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">Rval sdword ?</span><br><span class="line">Xval sdword 26</span><br><span class="line">Yval sdword 30</span><br><span class="line">ZVal sdword 40</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">;INC和DEC</span><br><span class="line">mov ax,100h</span><br><span class="line">inc ax</span><br><span class="line">dec ax</span><br><span class="line"></span><br><span class="line">;Rval=-Xval(Yval-Zval)</span><br><span class="line"></span><br><span class="line">;零标志符</span><br><span class="line">mov cx,1</span><br><span class="line">sub cx,1</span><br><span class="line">mov ax,0FFFFh</span><br><span class="line">inc ax</span><br><span class="line"></span><br><span class="line">;符号标志位</span><br><span class="line">mov cx,0</span><br><span class="line">sub cx,1</span><br><span class="line">mov ax,0FFFFh</span><br><span class="line">inc ax</span><br><span class="line"></span><br><span class="line">;进位标志位</span><br><span class="line">mov al,0FFh</span><br><span class="line">add al,1</span><br><span class="line"></span><br><span class="line">;溢出标志位</span><br><span class="line">mov al,+127</span><br><span class="line">add al,1</span><br><span class="line">mov al,-128</span><br><span class="line">sub al,1</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h3 id="4-3-与数据相关的运算符和伪指令"><a href="#4-3-与数据相关的运算符和伪指令" class="headerlink" title="4.3 与数据相关的运算符和伪指令"></a>4.3 与数据相关的运算符和伪指令</h3><p>运算符与伪指令不是可执行指令，反之，它们由汇编器进行分析。使用一些汇编语言伪指令<strong>可以获取数据地址和大小</strong>的信息:<br>OFFSET运算符返回的是一个变量与其所在段起始地址之间的距离（就相当于数组的首元素）。</p>
<p>PTR运算符可以重写操作数默认的大小类型</p>
<p>TYPE运算符返回的是一个操作数或数组中每个元素的大小(按字节计)。</p>
<p>LENGHTOF运算符返回的是数组中元素的个数</p>
<p>SIZEOF运算符返回的是数组初始化时使用的字节数</p>
<p>此外，LABEL伪指令可以用不同的大小类型来重新定义同一个变量。本章的运算符和伪指令只代表MASM支持的一小部分运算符</p>
<h4 id="4-3-1-OFFSET运算符"><a href="#4-3-1-OFFSET运算符" class="headerlink" title="4.3.1 OFFSET运算符"></a>4.3.1 OFFSET运算符</h4><p>OFFSET运算符<strong>返回数据标号的偏移量</strong>。这个偏移量按字节计算，表示的是该数据标号距离数据段起始地址的距离。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">bval byte ?</span><br><span class="line">wval word ?</span><br><span class="line">dval dword ?</span><br><span class="line">dval2 dword ?</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov esi,offset bval</span><br><span class="line">mov esi,offset wval</span><br><span class="line">mov esi,offset dval</span><br><span class="line">mov esi,offset dval2</span><br></pre></td></tr></table></figure>

<p>还可以用一个变量的偏移量来初始化另一个双字变量，从<strong>而有效地创建一个指针</strong>。(!)如下例所示，PArray就指向bigArray的起始地址:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">bighrray DNORD 500 DUP(?)</span><br><span class="line">pArray DMoRD bigArray</span><br></pre></td></tr></table></figure>

<p>下面的指令把该指针的值加载到ESI中，因此，这个ESI寄存器就可以<strong>指向数组的起始地址</strong>:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mov esi,pArray</span><br></pre></td></tr></table></figure>



<h4 id="4-3-2-ALIGN运算符"><a href="#4-3-2-ALIGN运算符" class="headerlink" title="4.3.2 ALIGN运算符"></a>4.3.2 ALIGN运算符</h4><p>ALIGN伪指令将一个空量对<strong>齐到字节边界</strong>、字边界，以字边界或段落边界。语法如下</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ALIGN bound</span><br></pre></td></tr></table></figure>

<p>Bound可取值有:1、2、4，8、16，当敢值为1时，则下一个变量对齐于1字节边界(默认情况)。当取值为2时，则下一个变量<strong>对齐于偶数地址</strong>，当此值为4时，<strong>则下一个变量地址为4的倍数</strong>。当取值为16时，则下个小量<strong>地址为16的倍数</strong>，哪一个段落的边界为了满足对齐要求，汇编器会在变量前插人一个成第个空字节。<strong>为什么要对齐数据</strong>?因为，对于存储于偶地址和奇地址的数据来说，CPU处理偶地址数据的速度要快得多</p>
<h4 id="4-3-3-PTR运算符"><a href="#4-3-3-PTR运算符" class="headerlink" title="4.3.3 PTR运算符"></a>4.3.3 PTR运算符</h4><p>PTR运算符可以用来<strong>重写</strong>一个<strong>已经被声明过的操作数</strong>的<strong>大小类型</strong></p>
<p>PTR必须与一个<strong>标准汇编数据类型</strong>一起使用</p>
<p><strong>将较小的值送入较大的目的操作数</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">wordlist word 5678h,1234h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov eax,dword ptr wordlist ;EAX=12345678</span><br></pre></td></tr></table></figure>

<p>第一个字复制到EAX的低部分，第二字复制到EAX的高部分</p>
<h4 id="4-3-4-TYPE运算符"><a href="#4-3-4-TYPE运算符" class="headerlink" title="4.3.4 TYPE运算符"></a>4.3.4 TYPE运算符</h4><p>TYPE运算符返回变量<strong>单个元素</strong>的大小，大小以字节为单位进行计算</p>
<h4 id="4-3-5-LENGTHOF运算符"><a href="#4-3-5-LENGTHOF运算符" class="headerlink" title="4.3.5 LENGTHOF运算符"></a>4.3.5 LENGTHOF运算符</h4><p>LENGTHOF运算符计算数组中的<strong>元素个数</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">myArray byte 10,20,30,40,50</span><br><span class="line">		byte 60,70,80,90,100</span><br></pre></td></tr></table></figure>

<p>length of my arrray 返回值为5</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">myArray byte 10,20,30,40,50, </span><br><span class="line">		byte 60,70,80,90,100</span><br></pre></td></tr></table></figure>

<p>添加了逗号以后，length of my arrray返回值为10</p>
<h4 id="4-3-6-SIZEOF运算符"><a href="#4-3-6-SIZEOF运算符" class="headerlink" title="4.3.6 SIZEOF运算符"></a>4.3.6 SIZEOF运算符</h4><p><strong>SIZEOF的运算符返回值等于LENGTHOF与TYPE返回值的乘积</strong></p>
<p>跟c语言的sizeof效果一样</p>
<h4 id="4-3-7-LABEL伪指令"><a href="#4-3-7-LABEL伪指令" class="headerlink" title="4.3.7 LABEL伪指令"></a>4.3.7 LABEL伪指令</h4><p>LABEL伪指令可以插人一个标号，并定义它的大小属性，但是不为这个标号分配存储空间。LABEL中可以使用所有的标准大小属性，如BYTE、WORD、DWORD、QWORD或TBYTE。LABEL常见的用法是，为数据段中定义的下一个变量提供不同的名称和大小属性。如下例所示，在变量val32前定义了一个变量，名称为val16，属性为WORD</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">va116 LADRL WORD</span><br><span class="line">val32 DWORD 12345678h</span><br><span class="line">.code</span><br><span class="line">mov ax,val16</span><br><span class="line">mov dx, [val16+2]</span><br></pre></td></tr></table></figure>

<p>vall6与val32<strong>共享同一个内存位置</strong>，<strong>LABEL伪指令自身不分配内存</strong></p>
<p>有时需要用两个较小的整数组成一个较大的就收。如下例所示，两个16位变量组成一个32位变量并加载到EAX中:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">LongValue LABEL DMORD</span><br><span class="line">val1 WORD 5678h</span><br><span class="line">va12 WORD 1234h</span><br><span class="line">.code</span><br><span class="line">mov eax, LongValue</span><br></pre></td></tr></table></figure>



<h3 id="4-4-间接寻址"><a href="#4-4-间接寻址" class="headerlink" title="4.4 间接寻址"></a>4.4 间接寻址</h3><p>直接寻址很少用于<strong>数组处理</strong>，因为，用常数偏移量来寻址多个数组元素时，直接寻址不实用。反之，会用寄存器作为指针(称为间接寻址)并控制该寄存器的值。如果一个操作数使用的是间接寻址，就称之为<strong>间接操作数</strong>。</p>
<p><strong>ESI储存的就是偏移量</strong></p>
<h4 id="4-4-1-间接操作数"><a href="#4-4-1-间接操作数" class="headerlink" title="4.4.1 间接操作数"></a>4.4.1 间接操作数</h4><p><strong>保护模式</strong></p>
<p>任何一个32位通用寄存器(EAX、EBX、ECX、EDX、ESI、EDI、EBP和<br>ESP)加上括号就能构成一个间接操作数。寄存器中存放的是数据的地址。示例如下，<strong>ESI存放的是byteVal的偏移量</strong>，MOV指令使用间接操作数作为源操作数，解析ESI中的偏移量，并将一个字节送入AL:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">byteVal BYTE 10h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov esi,oFFsET byteval</span><br><span class="line">mov al,[esi] ;访问的是地址，AL=10h</span><br></pre></td></tr></table></figure>



<h5 id="PTR与间接操作数一起使用"><a href="#PTR与间接操作数一起使用" class="headerlink" title="PTR与间接操作数一起使用"></a>PTR与间接操作数一起使用</h5><p>如果目的操作数也是间接操作数，那么新值将存入由寄存器提供地址的内存位置（！）</p>
<h4 id="4-4-2-数组"><a href="#4-4-2-数组" class="headerlink" title="4.4.2 数组"></a>4.4.2 数组</h4><p>间接操作数是步进遍历数组的理想工具。下例中,arrayB有3个字节，<strong>随着ESI不断加1,它就能顺序指向每一个字节</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">arrayb byte 10h,20h,30h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov esi,oFFsET arrayb</span><br><span class="line">mov al,[esi]</span><br><span class="line">inc esi</span><br><span class="line">mov al,[esi]</span><br><span class="line">inc esi</span><br><span class="line">mov al,[esi]</span><br></pre></td></tr></table></figure>

<p>实现了步进！</p>
<p><strong>示例：32位整数相加</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov esi,oFFsET arrayd</span><br><span class="line">mov eax,[esi]</span><br><span class="line">add esi,4</span><br><span class="line">add eax,[esi]</span><br><span class="line">add esi,4</span><br><span class="line">add eax,[esi]</span><br></pre></td></tr></table></figure>



<h4 id="4-4-3-变址操作数"><a href="#4-4-3-变址操作数" class="headerlink" title="4.4.3 变址操作数"></a>4.4.3 变址操作数</h4><p>变址操作数是指，在<strong>寄存器（而不是变量）上加上常数</strong>产生一个有效地址。每个32位通用寄存器都可以用作变址寄存器。MASM可以用不同的符号来表示变址操作数(括号是表示符号的一部分),下面给出的是两种符号形式的例子:</p>
<table>
<thead>
<tr>
<th>arrayB[esi]</th>
<th>[arrayB+esi]</th>
</tr>
</thead>
<tbody><tr>
<td>arrayD[esi]</td>
<td>[arrayD+esi]</td>
</tr>
</tbody></table>
<p>第一种形式是变量名加上寄存器。变量名由汇编器转换为常数，代表的是该变量的偏移量。<strong>数组元素之前，变址寄存器需要初始化为0</strong>:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">arrayB BYTE 10h,20h,30h</span><br><span class="line">.code</span><br><span class="line">mov esi,1</span><br><span class="line">mov al,arrayB[esi]</span><br></pre></td></tr></table></figure>

<p>byte+1,即20h会进到al里头</p>
<p>增加位移量变址寻址的第二种形式是寄存器加上常数偏移量:变址寄存器保存数组或结构的基址</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">arrayw word 1000h,2000h,3000h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov esi,offset arrayw</span><br><span class="line">mov ax,[esi]</span><br><span class="line">mov ax,[esi+2]</span><br><span class="line">mov ax,[esi+4]</span><br></pre></td></tr></table></figure>

<p><strong>变址操作数的比例因子</strong></p>
<p>就是用TYPE，使步进空间变得灵活</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">arrayd dword 1000h,2000h,3000h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov esi,2*type arrayd</span><br><span class="line">mov eax,arrayd[esi]</span><br></pre></td></tr></table></figure>

<p>INTEL的人员想出了<strong>比例因子</strong>这种东西。比例因子是数组元素的大小（字&#x3D;2，双字&#x3D;4，四字&#x3D;8）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">arrayd dword 1000h,2000h,3000h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">mov esi,2</span><br><span class="line">mov eax,arrayd[esi*type arrayd]</span><br></pre></td></tr></table></figure>

<p>他们认为这样让变换地址更加灵活</p>
<h4 id="4-4-4-指针"><a href="#4-4-4-指针" class="headerlink" title="4.4.4 指针"></a>4.4.4 指针</h4><p>如果<strong>一个变量</strong>包含另<strong>一个变量</strong>的地址，则该变量称为<strong>指针</strong>。指针是控制数组和数据结构的重要工具，因为，它包含的地址在运行时是可以修改的。比如，可以使用系统调用来分配(保留)一个内存块，再把这个块的地址保存在一个变量中。指针的大小受处理器当前模式(32位或64位)的影响。下例为32位的代码，ptrB包含了arrayB的偏移量:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">arrayB byte 10h,20h,30h,40h</span><br><span class="line">ptrB dword arrayB</span><br><span class="line">; 等价于 ptrB dword offset arrayB</span><br></pre></td></tr></table></figure>

<p>本书中的32位模式程序使用的是近指针，因此，它们保存在双字变量中</p>
<p><strong>使用TYPEDEF运算符</strong></p>
<p>typedef运算符可以创建用户定义类型，这些类型包含了定义变量时内置类型的所有状态。<strong>创建指针的理想工具</strong></p>
<p>下面声明创建一个新的数据类型就是<strong>一个字节指针</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pbyte typedef ptr byte</span><br></pre></td></tr></table></figure>

<p>这个声明放在靠近程序开始的地方，在数据段之前，然后，变量就可以用pbyte来定义</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">arrayb byte 10h,20h,30h,40h</span><br><span class="line">ptr1 pbyte ?</span><br><span class="line">ptr2 pbyte arrayB</span><br></pre></td></tr></table></figure>



<p><strong>示例程序Pointers</strong></p>
<p>指针定义放在.data前面，然后在.data中定义变量，加ptr是因为指针地址是32位的</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">pbyte typedef ptr byte ;字节指针</span><br><span class="line">pword typedef ptr word</span><br><span class="line">pdword typedef ptr dword</span><br><span class="line">.data</span><br><span class="line">arrayb byte 10h,20h,30h</span><br><span class="line">arrayw word 1,2,3</span><br><span class="line">arrayd dword 4,5,6</span><br><span class="line">ptr1 pbyte arrayb</span><br><span class="line">ptr2 pword arrayw</span><br><span class="line">ptr3 pdword arrayd</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov esi,ptr1</span><br><span class="line">	mov al,[esi]</span><br><span class="line">	mov esi,ptr2</span><br><span class="line">	mov ax,[esi]</span><br><span class="line">	mov esi,ptr3</span><br><span class="line">	mov eax,[esi+8] ;6，因为一个Dword是4</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h4 id="4-4-5-本节回顾"><a href="#4-4-5-本节回顾" class="headerlink" title="4.4.5 本节回顾"></a>4.4.5 本节回顾</h4><p>任何一个32位通用寄存器都可以用作间接操作数</p>
<p>至少EBX可以，但默认是esi</p>
<h3 id="4-5-JMP和LOOP指令"><a href="#4-5-JMP和LOOP指令" class="headerlink" title="4.5 JMP和LOOP指令"></a>4.5 JMP和LOOP指令</h3><p>无条件转移:无论什么情况都会转移到新地址。新地址加载到指令指针寄存器，使得程序在新地址进行执行。JMP指令实现这种转移。</p>
<p>条件转移:满足某种条件，则程序出现分支。各种条件转移指令还可以组合起来，形成条件逻辑结构。CPU基于ECX和标志寄存器的内容来解释真&#x2F;假条件。</p>
<h4 id="4-5-1-JMP指令"><a href="#4-5-1-JMP指令" class="headerlink" title="4.5.1 JMP指令"></a>4.5.1 JMP指令</h4><p>JMP指令<strong>无条件跳转到目标地址</strong>，该地址用代码标号来标识，并被汇编器转换为偏移量。语法如下所示:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">JMP destination</span><br></pre></td></tr></table></figure>

<p>创建一个情环JMP指令提供了一种简单的方法来创建循环，即跳转到循环开始时的标号:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">top:</span><br><span class="line">.</span><br><span class="line">.</span><br><span class="line">jmp top;不断地循环</span><br></pre></td></tr></table></figure>

<p>JMP是无条件的，因此循环会<strong>无休止地进行下去</strong>，除非找到其他方法退出循环。</p>
<p>明明可以举一个跳转到别处的例子，为什么要自己跳自己？</p>
<h4 id="4-5-2-LOOP指令"><a href="#4-5-2-LOOP指令" class="headerlink" title="4.5.2 LOOP指令"></a>4.5.2 LOOP指令</h4><p>LOOP指令，正式称为<strong>按照ECX计数器循环</strong>，将程序块重复特定次数。ECX自动成为计数器，<strong>每循环一次计数值减1</strong>。语法如下所示:</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">LooP deatination</span><br></pre></td></tr></table></figure>

<p>循环目标，必须距离<strong>当前地址计数器</strong>-128到+127字节范围内。LOOP指令的执行有两个步骤:第一步，ECX减1，第二步，将ECX与0比较。如果ECX不等于0，则跳转到由目标给出出的标号。否则，如果ECX等于0，则<strong>不发生跳转</strong>，并将控制传递到着环后面的指令。</p>
<p>实地址模式下，CX是LOOP指令的默认循环计数器，同时，<strong>LOOPD</strong>指令使用ECX为循环计数器，<strong>LOOPW</strong>指令使用CX为循环计数器</p>
<p><strong>不能将ECX初始化为0！！</strong>不然循环次数会非常大（-1后跳到65536），编译器会报错</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov ax,0</span><br><span class="line">	mov ecx,5</span><br><span class="line">L1:</span><br><span class="line">	inc ax</span><br><span class="line">	loop L1</span><br></pre></td></tr></table></figure>

<p>如果必须要修改ECX，那最好将ECX先用变量储存起来</p>
<p>涉及到<strong>循环嵌套</strong></p>
<p>对于一般规则，多余两重的循环嵌套难以编写，需要多重循环的话，则需要用子程序实现</p>
<h4 id="4-5-3-在Visual-Studio调试器中显示数组"><a href="#4-5-3-在Visual-Studio调试器中显示数组" class="headerlink" title="4.5.3 在Visual Studio调试器中显示数组"></a>4.5.3 在Visual Studio调试器中显示数组</h4><p>Debug-&gt;Memory-&gt;Memory</p>
<p>在内存窗口上端的Address栏里，键入符号和数组名称，然后ENTER</p>
<p>例如&amp;arrayb</p>
<p>右键有更多选项</p>
<h4 id="4-5-4-整数数组求和"><a href="#4-5-4-整数数组求和" class="headerlink" title="4.5.4 整数数组求和"></a>4.5.4 整数数组求和</h4><p>在刚开始编程时，几乎没有任务比计算数组元素总和更常见了。汇编语言实现数组求和步骤如下:<br>1)指定一个寄存器作变址操作数，存放数组地址<br>2)循环计数器初始化为数组的长度。<br>3)指定一个寄存器存放累积和数，并赋值为0.<br>4)创建标号来标记循环开始的地方。<br>5)在循环体内，将和数与一个数组元素相加。<br>6)指向下一个数组元素。<br>7)用LOOP指令重复循环<br>步骤1到步骤3可以按照任何顺序执行。下面的短程序实现对一个16位整数数组求和。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">.data</span><br><span class="line">intarray dword 10000h,20000h,30000h,40000h</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov edi,offset intarray</span><br><span class="line">	mov ecx,lengthof intarray</span><br><span class="line">	mov eax,0</span><br><span class="line">L1:</span><br><span class="line">	add eax,[edi]</span><br><span class="line">	add edi,type intarray</span><br><span class="line">	loop L1</span><br></pre></td></tr></table></figure>



<h4 id="4-5-5-复制字符串"><a href="#4-5-5-复制字符串" class="headerlink" title="4.5.5 复制字符串"></a>4.5.5 复制字符串</h4><p>在汇编语言里，用<strong>循环</strong>来复制一个字符串，而字符串表示为<strong>带有一个空终止值</strong>的字节数组</p>
<p>从一个内存空间到另外一个内存空间</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">source byte &quot;This is the source string&quot;,0</span><br><span class="line">target byte sizeof source DUP(0)</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov esi,0</span><br><span class="line">	mov ecx,sizeof source</span><br><span class="line">L1:</span><br><span class="line">	mov al,source[esi]</span><br><span class="line">	mov target[esi],al</span><br><span class="line">	inc esi</span><br><span class="line">	loop L1</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h3 id="4-6-64位编程"><a href="#4-6-64位编程" class="headerlink" title="4.6 64位编程"></a>4.6 64位编程</h3><p>（放在以后）</p>
<p>内存数据格式由dword变qword</p>
<h2 id="5-过程"><a href="#5-过程" class="headerlink" title="5 过程"></a>5 过程</h2><p>两个代码库，Irvine32和Irvine64 包含有用工具进行简化输入输出</p>
<h3 id="5-1-堆栈操作"><a href="#5-1-堆栈操作" class="headerlink" title="5.1 堆栈操作"></a>5.1 堆栈操作</h3><p>堆栈是FILO，后进先出</p>
<h4 id="5-1-1-运行时堆栈（32位模式）"><a href="#5-1-1-运行时堆栈（32位模式）" class="headerlink" title="5.1.1 运行时堆栈（32位模式）"></a>5.1.1 运行时堆栈（32位模式）</h4><p>直接由CPU的硬件支持，是过程调用与返回的基本机制</p>
<p>运行时堆栈是<strong>内存数组</strong>，CPU用ESP（扩展堆栈指针,extended stack pointer)寄存器对其进行直接管理，该寄存器被称为<strong>堆栈指针寄存器</strong>（stack pointer register)。32位模式下，ESP寄存器存放的是堆栈中某个位置的32位偏移量。ESP基本上<strong>不会直接被程序员控制</strong>，反之，它是用<strong>CALL、RET、PUSH和POP</strong>等指令间接进行修改。</p>
<h5 id="1-入栈操作"><a href="#1-入栈操作" class="headerlink" title="1.入栈操作"></a>1.入栈操作</h5><p>32位入栈操作把栈顶指针减4，再将数值复制到栈顶指针指向的堆栈位置。图5-3展示了把000000A5压入堆栈的结果，堆栈中已经有一个数值（00000006）。注意，<strong>ESP寄存器总是指向添加，或压入到栈顶的最后一个数值。图中显示的堆栈顺序与之前示例给出的盘堆栈顺序相反，</strong>这是因为运行时堆栈在内存中是向下生长的<strong>，</strong>即从高地址向低地址扩展。**</p>
<h5 id="2-出栈操作"><a href="#2-出栈操作" class="headerlink" title="2.出栈操作"></a>2.出栈操作</h5><p>出栈操作从堆栈删除数据。数值弹出堆栈后，栈顶指针增加（按堆栈元素大小）</p>
<p>ESP之下的堆栈域在逻辑上是空白的，当前程序下一次执行任何数值入栈操作指令都可以覆盖这个区域。（！）</p>
<h5 id="3-堆栈应用"><a href="#3-堆栈应用" class="headerlink" title="3.堆栈应用"></a>3.堆栈应用</h5><p>运行时堆栈在程序中有一些重要用途：<br>    当寄存器用于多个目的时，堆栈可以作为寄存器的一个方便的临时保存区。在寄存器被修改后，还可以恢复其初始值。<br>    执行CALL指令时，CPU在堆栈中保存当前过程的返回地址。<br>    调用过程时，输入数值也被称为<strong>参数</strong>，通过将其压入堆栈实现参数传递。</p>
<p>​	堆栈也为过程局部变量提供了临时存储区域。</p>
<h4 id="5-1-2-PUSH和POP指令"><a href="#5-1-2-PUSH和POP指令" class="headerlink" title="5.1.2 PUSH和POP指令"></a>5.1.2 PUSH和POP指令</h4><h5 id="1-PUSH指令"><a href="#1-PUSH指令" class="headerlink" title="1.PUSH指令"></a>1.PUSH指令</h5><p><strong>PUSH指令首先减少ESP的值</strong>，再将源操作数复制到堆栈。操作数是16位的，则ESP减2，操作数是32位的，则ESP减4。</p>
<h5 id="2-POP指令"><a href="#2-POP指令" class="headerlink" title="2.POP指令"></a>2.POP指令</h5><p>POP指令首先把ESP指向的堆栈元素内容复制到一个16位或32位目的操作数中，再增加ESP的值。如果操作数是16位的，ESP加2，如果操作数是32位的，ESP加4</p>
<h5 id="3-PUSHFD和POPFD指令"><a href="#3-PUSHFD和POPFD指令" class="headerlink" title="3.PUSHFD和POPFD指令"></a>3.PUSHFD和POPFD指令</h5><p>PUSHFD指令把32位<strong>EFLAGS寄存器</strong>内容<strong>压入堆栈</strong>，而POPFD指令则把栈顶单元<strong>内容弹出</strong>到EFLAGS寄存器</p>
<p><strong>不能用MOV指令把标识寄存器内容复制给一个变量</strong>(?)，因此，<strong>PUSHFD可能就是保存标志位的最佳途径</strong>。有些时候保存标志寄存器的副本是非常有用的，这样之后就可以恢复标志寄存器原来的值。</p>
<p>当用这种方式使用入栈和出栈指令时，必须确保程序的执行路径不会跳过POPFD指令。当程序随着时间不断修改时，很难记住所有入栈和出栈指令的位置。因此，<strong>精确的文档</strong>就显得至关重要！<br>一种不容易出错的保存和恢复标识寄存器的方法是：将它们压入堆栈后，立即弹出给一个变量：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.data </span><br><span class="line">saveFlags DWORD ?</span><br><span class="line">.code</span><br><span class="line">pushfd ;标识寄存器内容入栈</span><br><span class="line">pop saveFlags;复制给一个变量</span><br></pre></td></tr></table></figure>

<p>下述语句从同一个变量中恢复标识寄存器内容</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">push saveFlags ;被保存的标识入栈</span><br><span class="line">popfd ;复制给标识寄存器</span><br></pre></td></tr></table></figure>



<h5 id="4-PUSHAD-PUSHA-POPAD-POPA"><a href="#4-PUSHAD-PUSHA-POPAD-POPA" class="headerlink" title="4.PUSHAD,PUSHA,POPAD,POPA"></a>4.PUSHAD,PUSHA,POPAD,POPA</h5><p>PUSHAD指令按照EAX、ECX、EDX、EBX、ESP(执行PUSHAD之前的值）、EBP、ESI和EDI的<strong>顺序</strong>，将<strong>所有</strong>32位通用寄存器<strong>压入堆栈</strong>。</p>
<p>POPAD指令按照相反顺序将同样的寄存器<strong>弹出堆栈</strong></p>
<p>PUSHA指令按序（AX、CX、DX、BX、SP、BP、SI和DI)将16位通用寄存器<strong>压入堆栈</strong>。POPA指令按照相反顺序将同样的寄存器<strong>弹出堆栈</strong></p>
<p>必须要指出，上述示例有一个<strong>重要的例外</strong>：过程用一个或多个寄存器来返回结果时，不应使用PUSHA和PUSHAD</p>
<h5 id="示例：字符串反转"><a href="#示例：字符串反转" class="headerlink" title="示例：字符串反转"></a>示例：字符串反转</h5><p>现在查看名为RevStr的程序：在一个字符串上循环，将每个字符压入堆栈，再把这些字符从堆栈中弹出（相反顺序），并保存回同一个字符串变量。由于堆栈是LIFO（后进先出）结构，字符串中的字母顺序就发生了翻转</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">aname byte &quot;Mocus EZ&quot;,0</span><br><span class="line">namesize = ($-aname)-1</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov ecx,namesize</span><br><span class="line">	mov esi,0</span><br><span class="line">L1:</span><br><span class="line">	movzx eax,aname[esi]</span><br><span class="line">	push eax</span><br><span class="line">	inc esi</span><br><span class="line">	loop L1</span><br><span class="line"></span><br><span class="line">	mov ecx,namesize</span><br><span class="line">	mov esi,0</span><br><span class="line"></span><br><span class="line">L2:</span><br><span class="line">	pop eax</span><br><span class="line">	mov aname[esi],al</span><br><span class="line">	inc esi</span><br><span class="line">	LOOP L2</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h3 id="5-2-定义并使用过程"><a href="#5-2-定义并使用过程" class="headerlink" title="5.2 定义并使用过程"></a>5.2 定义并使用过程</h3><p>如果读者已经学过了高级编程语言，那么就会知道将程序分割为<strong>子过程</strong>（subroutine)是多么有用。一个复杂的问题常常要分解为相互独立的任务，这样才易于被理解、实现以及有效地测试。在汇编语言中，通常用术语过程（procedure)来指代子程序。在其他语言中，子程序也被称为<strong>方法或函数</strong>。<br>就面向对象编程而言，单个类中的函数或方法大致相当于封装在一个汇编语言模块中的过程和数据集合。汇编语言出现的时间远早于面向对象编程，因此它不具备面向对象编程中的形式化结构。汇编程序员必须在程序中实现自己的形式化结构。（啊这）</p>
<h4 id="5-2-1-PROC伪指令"><a href="#5-2-1-PROC伪指令" class="headerlink" title="5.2.1 PROC伪指令"></a>5.2.1 PROC伪指令</h4><h5 id="1-定义过程"><a href="#1-定义过程" class="headerlink" title="1.定义过程"></a>1.定义过程</h5><p>过程可以非正式地定义为：由返回语句结束的已命名的语句块。过程用<strong>PROC和ENDP</strong>伪指令来定义，并且必须为其<strong>分配一个名字</strong>（有效标识符）。到目前为止，所有编写的程序都包含了一个名为main的过程</p>
<p>当在程序启动过程之外创建一个过程时，就<strong>用RET指令来结束它</strong>RET强制CPU返回到该过程被调用的位置（？？）</p>
<h5 id="2-过程中的标号"><a href="#2-过程中的标号" class="headerlink" title="2.过程中的标号"></a>2.过程中的标号</h5><p>默认情况下，标号只在其被定义的过程中可见。这个规则常常影响到跳转和循环指令。在下面的例子中，名为Destination的标号必须与JMP指令位于同一个过程中：<br>    jmp Destination解决这个限制的方法是定义全局标号，即在名字后面加双冒号（：：）：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Destination::</span><br></pre></td></tr></table></figure>

<p>​    就程序设计而言，跳转或循环到当前过程之外不是个好主意。过程用自动方式返回并调整运行时堆栈。如果直接跳出一个过程，则运行时堆栈很容易被损坏。（这是什么东西？）</p>
<p>用高级语言，如C和C++，编写的函数，通常用AL返回8位的值，用AX返回16位的值，用EAX返回32位的值。</p>
<h4 id="5-2-2-CALL和RET指令"><a href="#5-2-2-CALL和RET指令" class="headerlink" title="5.2.2 CALL和RET指令"></a>5.2.2 CALL和RET指令</h4><p>CALL指令调用一个过程，<strong>指挥处理器从新的内存地址开始执行</strong>。过程<strong>使用RET（从过程返回）指令</strong>将处理器转回到该过程被调用的程序点上。从物理上来说，CALL指令将其返回地址压入堆栈，再把被调用过程的地址复制到指令指针寄存器。当过程准备返回时，它的RET指令从堆栈把返回地址弹回到指令指针寄存器。32位模式下，CPU执行的指令由EIP（指令指针寄存器）在内存中指出。16位模式下，由IP指出指令。</p>
<h5 id="调用和返回示例"><a href="#调用和返回示例" class="headerlink" title="调用和返回示例"></a>调用和返回示例</h5><p>假设在main过程中，CALL指令位于偏移量为00000020处。通常，这条指令需要5个字节的机器码，因此，下一条语句（本例中为一条MOV指令)就位于偏移量为00000025处：</p>
<p>MySub的地址加载到EIP。执行MySub中的全部指令直到RET指令。当执行RET指令时，ESP指向的堆栈数值被弹出到EIP。在步骤2中，ESP的数值增加，从而指向堆栈中的前一个值（步骤2）。</p>
<p><strong>当CALL指令执行时，调用之后的地址（00000025）被压入堆栈</strong>，MySub的地址加载到EIP。执行MySub中的全部指令直到RET指令。当执行RET指令时，ESP指向的堆栈数值被弹出到EIP。在步骤2中，ESP的数值增加，从而指向堆栈中的前一个值（步骤2）。</p>
<p>下面这个做了一个示范样例，不涉及ESP和ESP的直接调用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">aname byte &quot;Mocus EZ&quot;,0</span><br><span class="line">namesize = ($-aname)-1</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">sumof proc</span><br><span class="line">	add eax,ebx</span><br><span class="line">	add eax,ecx</span><br><span class="line">	ret</span><br><span class="line">sumof endp</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">main PROC</span><br><span class="line">	mov eax,5</span><br><span class="line">	mov ebx,3</span><br><span class="line">	mov ecx,6</span><br><span class="line">	call sumof</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h4 id="5-2-3-过程调用嵌套"><a href="#5-2-3-过程调用嵌套" class="headerlink" title="5.2.3 过程调用嵌套"></a>5.2.3 过程调用嵌套</h4><p>书本图太多，类比C语言里的函数调用，ESP和堆栈的弹入和弹出</p>
<p>一般说来，堆栈结构用于程序需要按照特定顺序返回的情况。</p>
<h4 id="5-2-4-向过程传递寄存器参数"><a href="#5-2-4-向过程传递寄存器参数" class="headerlink" title="5.2.4 向过程传递寄存器参数"></a>5.2.4 向过程传递寄存器参数</h4><p>向过程传递数组的偏移量以及指定数组元素个数的整数。这些内容被称为<strong>参数</strong>（或输入参数）。在汇编语言中，经常用<strong>通用寄存器来传递参数</strong>。<br>在前面的章节中创建了一个简单的过程SumOf，计算EAX、EBX和ECX中的整数之和。在main调用SumOf之前，将数值分配给EAX、EBX和ECX</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">sum dword ?</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">sumof proc</span><br><span class="line">	add eax,ebx</span><br><span class="line">	add eax,ecx</span><br><span class="line">	ret</span><br><span class="line">sumof endp</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">main PROC</span><br><span class="line">	mov eax,5</span><br><span class="line">	mov ebx,3</span><br><span class="line">	mov ecx,6</span><br><span class="line">	call sumof</span><br><span class="line">	mov sum,eax</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h4 id="5-2-5-示例：整数数组求和"><a href="#5-2-5-示例：整数数组求和" class="headerlink" title="5.2.5 示例：整数数组求和"></a>5.2.5 示例：整数数组求和</h4><p>下面这个案例可通用</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">array dword 10000h,20000h,30000h,40000h,50000h</span><br><span class="line">thesum dword ?</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">arraysum proc</span><br><span class="line">	push esi</span><br><span class="line">	push ecx</span><br><span class="line">	mov eax,0</span><br><span class="line">L1:</span><br><span class="line">	add eax,[esi]</span><br><span class="line">	add esi,type dword</span><br><span class="line">	loop L1</span><br><span class="line">	pop ecx</span><br><span class="line">	pop esi</span><br><span class="line">	ret</span><br><span class="line">arraysum endp</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">main PROC</span><br><span class="line">	mov esi,offset array</span><br><span class="line">	mov ecx,lengthof array </span><br><span class="line">	;所以为什么说lengthof有用的原因</span><br><span class="line">	;当时写了一个错的add esi,type dword</span><br><span class="line">	call arraysum</span><br><span class="line">	mov thesum,eax</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<h4 id="5-2-6-保存和恢复寄存器"><a href="#5-2-6-保存和恢复寄存器" class="headerlink" title="5.2.6 保存和恢复寄存器"></a>5.2.6 保存和恢复寄存器</h4><p>在ArraySum示例中，ECX和ESI在过程开始时被压入堆栈，在过程结束时被弹出堆栈。<strong>这是大多数过程修改寄存器的典型操作</strong>。总是保存和恢复被过程修改的寄存器，将使得调用程序确保自己的寄存器值不会被覆盖。</p>
<p>USES运算符USES运算符与PROC伪指令一起使用，让程序员列出在该过程中修改的所有寄存器名。USES告诉汇编器做两件事情：</p>
<p>第一，在过程开始时生成PUSH指令，将寄存器保存到堆栈；</p>
<p>第二，在过程结束时生成POP指令，从堆栈恢复寄存器的值。</p>
<p>USES运算符紧跟在PROC之后，其后是位于同一行上的寄存器列表，表项之间用空格符或制表符（不是逗号）分隔。（妙啊！）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">array dword 10000h,20000h,30000h,40000h,50000h</span><br><span class="line">thesum dword ?</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">arraysum proc uses esi ecx</span><br><span class="line">	mov eax,0</span><br><span class="line">L1:</span><br><span class="line">	add eax,[esi]</span><br><span class="line">	add esi,type dword</span><br><span class="line">	loop L1</span><br><span class="line">	ret</span><br><span class="line">arraysum endp</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">main PROC</span><br><span class="line">	mov esi,offset array</span><br><span class="line">	mov ecx,lengthof array </span><br><span class="line">	call arraysum</span><br><span class="line">	mov thesum,eax</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>节省掉push和pop</p>
<h5 id="例外情况！！！"><a href="#例外情况！！！" class="headerlink" title="例外情况！！！"></a>例外情况！！！</h5><p>当寄存器要返回数值时，就不能这么做（比如EAX要带着运算结果会main，汇编没用形式参数这一说）</p>
<h3 id="5-3-链接到外部库"><a href="#5-3-链接到外部库" class="headerlink" title="5.3 链接到外部库"></a>5.3 链接到外部库</h3><p>使用Irvine32链接库，简化控制台应用编写</p>
<p>Irvine32链接库只能用于32位模式下运行的程序。它包含了链接到MS-Windows API的过程，生成输入输出。对64位应用程序来说，Irvine64链接库的限制更多，它仅限于基本显示和字符串操作。</p>
<h4 id="5-3-1-背景知识"><a href="#5-3-1-背景知识" class="headerlink" title="5.3.1 背景知识"></a>5.3.1 背景知识</h4><p>当程序进行汇编时，汇编器将不指定CALL指令的目标地址，它知道这个地址将由链接器指定。链接器在链接库中寻找WriteString，并把库中适当的机器指令复制到程序的可执行文件中。同时，它把WriteString的地址插入到CALL指令。如果被调用过程不在链接库中，链接器就发出错误信息，且不会生成可执行文件。</p>
<h5 id="链接命令选项"><a href="#链接命令选项" class="headerlink" title="链接命令选项"></a>链接命令选项</h5><p>链接器工具把一个程序的目标文件与一个或多个目标文件以及链接库组合在一起。</p>
<p>32位程序链接kernel32.lib文件是Microsoft Windows平台软件开发工具（SoftwareDevelopment Kit)的一部分，它包含了kernel32.dll文件中系统函数的链接信息。kernel32.dll文件是MS-Windows的一个基本组成部分，被称为动态链接库（dynamic link library)。它含有的可执行函数实现基于字符的输入输出。</p>
<p>链接到在第1章到第10章中，程序都链接到Irvine32.lib或可以链接到者Irvine64.obj。第11章说明了如何将程序直接链接到kermel32.lib执行kernel32.lib。</p>
<h3 id="5-4-Irvine32-链接库"><a href="#5-4-Irvine32-链接库" class="headerlink" title="5.4 Irvine32 链接库"></a>5.4 Irvine32 链接库</h3><h4 id="5-4-1-创建库的动机"><a href="#5-4-1-创建库的动机" class="headerlink" title="5.4.1 创建库的动机"></a>5.4.1 创建库的动机</h4><p><strong>注意，数字是按照逆序生成，插入缓冲区，从后往前移动</strong>。然后，数字按照正序写到控制台。虽然这段代码简单到足以用C&#x2F;C++实现，但是如果是在汇编语言中，它还需要一些高级技巧。</p>
<p>电子PDF142页，有详细过程</p>
<h4 id="5-4-2-概述控制台窗口"><a href="#5-4-2-概述控制台窗口" class="headerlink" title="5.4.2 概述控制台窗口"></a>5.4.2 概述控制台窗口</h4><p>控制台窗口（console window)（或命令窗口command window)是显示命令提示符时，由MS-Windows生成的一个纯文本窗口。</p>
<p>文件句柄（file handle)是一个32位整数，<strong>Windows操作系统用它来标识当前打开的文件</strong>。当用户程序调用一个Windows服务来打开或创建文件时，操作系统就创建一个新的文件句柄，并使其对用户程序可用。<strong>每当程序调用OS服务方法来读写该文件时，就必须将这个文件句柄作为参数传递给服务方法</strong>。</p>
<p><strong>注意：</strong>如果用户程序调用Irvine32链接库中的过程，就必须总是将这个32位数值压入运行时堆栈；如果不这样做，被库调用的Win32控制台函数就不能正常工作。（！）</p>
<h4 id="5-4-3-过程详细说明"><a href="#5-4-3-过程详细说明" class="headerlink" title="5.4.3 过程详细说明"></a>5.4.3 过程详细说明</h4><h5 id="CloseFile"><a href="#CloseFile" class="headerlink" title="CloseFile"></a>CloseFile</h5><p>CloseFile 过程关闭之前已经创建或打开的文件（参见CreateOutputFile和OpenInputFile)。该文件用一个32位整数的句柄来标识，句柄由EAX传递。如果文件成功关闭，EAX中的返回值就是非零的</p>
<p>（电子PDF145页开始，到154页，太多了，不写了）</p>
<h4 id="5-4-4-库测试程序"><a href="#5-4-4-库测试程序" class="headerlink" title="5.4.4 库测试程序"></a>5.4.4 库测试程序</h4><p>这些库是书作者写的，难道微软官方就不给库嘛？</p>
<h5 id="测试1"><a href="#测试1" class="headerlink" title="测试1"></a>测试1</h5><p>写一个程序，演示用屏幕颜色输入&#x2F;输出整数</p>
<p>(居然不是标准格式，那些.386 flat全部没有)</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">; Library Test #1: Integer I/O   (TestLib1.asm)</span><br><span class="line"></span><br><span class="line">; Tests the Clrscr, Crlf, DumpMem, ReadInt, </span><br><span class="line">; SetTextColor, WaitMsg, WriteBin, WriteHex, </span><br><span class="line">; and WriteString procedures.</span><br><span class="line"></span><br><span class="line">INCLUDE Irvine32.inc</span><br><span class="line">.data</span><br><span class="line">arrayD     DWORD 1000h,2000h,3000h</span><br><span class="line">prompt1    BYTE &quot;Enter a 32-bit signed integer: &quot;,0</span><br><span class="line">dwordVal   DWORD ?</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">; Set text color to yellow text on blue background:</span><br><span class="line">	mov	eax,yellow + (blue * 16)</span><br><span class="line">	call	SetTextColor</span><br><span class="line">	call	Clrscr			; clear the screen</span><br><span class="line"></span><br><span class="line">; Display the array using DumpMem.</span><br><span class="line">	mov	esi,OFFSET arrayD	; starting OFFSET</span><br><span class="line">	mov	ecx,LENGTHOF arrayD	; number of units in dwordVal</span><br><span class="line">	mov	ebx,TYPE arrayD	; size of a doubleword</span><br><span class="line">	call	DumpMem			; display memory</span><br><span class="line">	call	Crlf				; new line</span><br><span class="line"></span><br><span class="line">; Ask the user to input a signed decimal integer.</span><br><span class="line">	mov	edx,OFFSET prompt1</span><br><span class="line">	call	WriteString</span><br><span class="line">	call	ReadInt			; input the integer</span><br><span class="line">	mov	dwordVal,eax		; save in a variable</span><br><span class="line"></span><br><span class="line">; Display the integer in decimal, hexadecimal, and binary.</span><br><span class="line">	call	Crlf				; new line</span><br><span class="line">	call	WriteInt			; display in signed decimal</span><br><span class="line">	call	Crlf</span><br><span class="line">	call	WriteHex			; display in hexadecimal</span><br><span class="line">	call	Crlf</span><br><span class="line">	call	WriteBin			; display in binary</span><br><span class="line">	call	Crlf</span><br><span class="line">	call	WaitMsg			; &quot;Press any key...&quot;</span><br><span class="line"></span><br><span class="line">; Return console window to default colors.</span><br><span class="line">	mov	eax,lightGray + (black * 16)</span><br><span class="line">	call	SetTextColor</span><br><span class="line">	call	Clrscr</span><br><span class="line">	exit</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h5 id="测试3"><a href="#测试3" class="headerlink" title="测试3"></a>测试3</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">; This program adds and subtracts 32-bit integers</span><br><span class="line">; and stores the sum in a variable.</span><br><span class="line"> </span><br><span class="line">INCLUDE Irvine32.inc</span><br><span class="line"> </span><br><span class="line">.data</span><br><span class="line">outer=3</span><br><span class="line">start dword ?</span><br><span class="line">msg1 byte &quot;Please wait&quot;,0dh,0ah,0</span><br><span class="line">msg2 byte &quot;milliseconds:&quot;</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">    mov edx,offset msg1</span><br><span class="line">    call writestring</span><br><span class="line"></span><br><span class="line">    call getmseconds</span><br><span class="line">    mov start,eax</span><br><span class="line"></span><br><span class="line">    mov ecx,outer</span><br><span class="line">L1: call innerloop</span><br><span class="line">    loop L1</span><br><span class="line"></span><br><span class="line">    call getmseconds</span><br><span class="line">    sub eax,start</span><br><span class="line"></span><br><span class="line">    mov edx,offset msg2</span><br><span class="line">    call writestring</span><br><span class="line">    call writedec</span><br><span class="line">    call crlf</span><br><span class="line">    exit</span><br><span class="line">main ENDP</span><br><span class="line"></span><br><span class="line">innerloop proc</span><br><span class="line">    push ecx</span><br><span class="line">    mov ecx,0FFFFFFFh</span><br><span class="line">L1: mul eax</span><br><span class="line">    mul eax</span><br><span class="line">    mul eax</span><br><span class="line">    loop L1</span><br><span class="line">    pop ecx</span><br><span class="line">    ret</span><br><span class="line">innerloop ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h3 id="5-5-64位汇编编程"><a href="#5-5-64位汇编编程" class="headerlink" title="5.5 64位汇编编程"></a>5.5 64位汇编编程</h3><p>（未完待续）</p>
<h2 id="6-条件处理"><a href="#6-条件处理" class="headerlink" title="6 条件处理"></a>6 条件处理</h2><p>使用本章的工具实现理论计算机科学最根本的结构之一：有限状态机</p>
<h3 id="6-1-条件分支"><a href="#6-1-条件分支" class="headerlink" title="6.1 条件分支"></a>6.1 条件分支</h3><p>高级语言的if和swit</p>
<h3 id="6-2-布尔和比较指令"><a href="#6-2-布尔和比较指令" class="headerlink" title="6.2 布尔和比较指令"></a>6.2 布尔和比较指令</h3><p>XOR 异或操作</p>
<p>NOT 非操作</p>
<p>TEST 源操作数和目的操作数</p>
<h4 id="6-2-1-CPU状态标志"><a href="#6-2-1-CPU状态标志" class="headerlink" title="6.2.1 CPU状态标志"></a>6.2.1 CPU状态标志</h4><p>布尔指令影响<strong>零标志位、进位标志位、符号标志位、溢出标志位和奇偶标志位</strong>。下面简单回顾一下这些标志位的含义：<br>    ·操作结果等于0时，零标志位置1。<br>    ·操作使得目标操作数的最高位有进位时，进位标志位置1。<br>    ·符号标志位是目标操作数高位的副本，如果标志位置1，表示是负数；标志位清0，表示是正数。（假设0为正。）</p>
<p>·指令产生的结果超出了有符号目的操作数范围时，溢出标志位置1。<br>·指令使得目标操作数低字节中有偶数个1时，奇偶标志位置1。</p>
<h4 id="6-2-2-AND指令符"><a href="#6-2-2-AND指令符" class="headerlink" title="6.2.2 AND指令符"></a>6.2.2 AND指令符</h4><p>AND指令可以清除一个操作数中的1个位或多个位，同时又不影响其他位。这个技术就称为<strong>位屏蔽</strong>，就像在粉刷房子时，用遮盖胶带把不用粉刷的地方（如窗户）盖起来。例如，假设要将一个控制字节从AL寄存器复制到硬件设备。并且当控制字节的位0和位3等于0时，该设备复位。</p>
<h5 id="将字符转换为大写"><a href="#将字符转换为大写" class="headerlink" title="将字符转换为大写"></a>将字符转换为大写</h5><p>AND指令提供了一种简单的方法将字符从小写转换为大写。如果对比大写A和小写a的ASCIⅡ码，就会发现只有位5不同</p>
<p>测试样例（陷入死循环）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">array byte 50 DUP(?)</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov ecx,lengthof array</span><br><span class="line">	mov esi,offset array</span><br><span class="line">	L1:</span><br><span class="line">	and byte ptr [esi],11011111b</span><br><span class="line">	inc esi</span><br><span class="line">	loop L1</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h4 id="6-2-3-OR指令"><a href="#6-2-3-OR指令" class="headerlink" title="6.2.3 OR指令"></a>6.2.3 OR指令</h4><p>标志位OR指令总是清除进位和溢出标志位，并根据目标操作数的值来修改符号标志位、零标志位和奇偶标志位。比如，可以将一个数与它自身（或0）进行OR运算，来获取该数值的某些信息</p>
<p>（见电子PDF172页，纸质151页）</p>
<h4 id="6-2-4-位映射集"><a href="#6-2-4-位映射集" class="headerlink" title="6.2.4 位映射集"></a>6.2.4 位映射集</h4><p>应用可以用位向量（或位映射）把一个二进制数中的位映射为数组中的对象</p>
<h5 id="补集"><a href="#补集" class="headerlink" title="补集"></a>补集</h5><p>可以用NOT指令生成</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov eax,SetX</span><br><span class="line">not eax</span><br></pre></td></tr></table></figure>



<h5 id="交集"><a href="#交集" class="headerlink" title="交集"></a>交集</h5><p>AND指令可以生成位向量来表示两个集合的交集</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov eax,SetX</span><br><span class="line">and eax,SetY</span><br></pre></td></tr></table></figure>

<p>很难想象还有更快捷的方法生成交集。对于更大的集合来说，它所需要的位超过了单个寄存器的容量，因此，需要用循环来实现所有位的AND运算。</p>
<h5 id="并集"><a href="#并集" class="headerlink" title="并集"></a>并集</h5><p>OR指令生成位图表示两个集合的并集</p>
<h4 id="6-2-5-XOR指令"><a href="#6-2-5-XOR指令" class="headerlink" title="6.2.5 XOR指令"></a>6.2.5 XOR指令</h4><p>同0输出1 同1输出0 相异输出1</p>
<p>两次XOR，输出为原有值</p>
<h5 id="检查奇偶标志位"><a href="#检查奇偶标志位" class="headerlink" title="检查奇偶标志位"></a>检查奇偶标志位</h5><p>一个既能检查数的奇偶性，又不会修改其数值的有效方法是，将该数与0进行异或运算：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mov al,10110101b；5个1，奇校验</span><br><span class="line">xor al,0；奇偶标志位清0（奇）</span><br><span class="line">mov al,11001100b；4个1，偶校验</span><br><span class="line">xor al,0；奇偶标志位置1（偶）</span><br></pre></td></tr></table></figure>

<p>Visual Studio用PE&#x3D;1表示偶校验，PE&#x3D;0表示奇校验</p>
<h5 id="16为奇偶性以此类推"><a href="#16为奇偶性以此类推" class="headerlink" title="16为奇偶性以此类推"></a>16为奇偶性以此类推</h5><p>对16位整数来说，可以通过将其高字节和低字节进行异或运算来检测数的奇偶性：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov ax,64C1h ；0110010011000001</span><br><span class="line">xor ah,al；奇偶标志位置1（偶）</span><br></pre></td></tr></table></figure>

<p>奇偶标志位置1（偶）将每个寄存器中的置1位(等于1的位)想象为一个8位集合中的成员。XOR指令把两个集合交集中的成员清0，<strong>并形成了其余位的并集</strong>。这个并集的奇偶性与整个16位整数的奇偶性相同。</p>
<h4 id="6-2-6-NOT-指令"><a href="#6-2-6-NOT-指令" class="headerlink" title="6.2.6 NOT 指令"></a>6.2.6 NOT 指令</h4><p>可翻转操作数的所有为，结果被成为反码</p>
<h4 id="6-2-7-TEST指令"><a href="#6-2-7-TEST指令" class="headerlink" title="6.2.7 TEST指令"></a>6.2.7 TEST指令</h4><p><strong>TEST指令在两个操作数的对应位之间进行AND操作</strong>，并根据运算结果设置符号标志位、零标志位和奇偶标志位。</p>
<p>TEST指令与AND指令<strong>唯一不同</strong>的地方是，TEST指令<strong>不修改目标操作数</strong>。TEST指令允许的操作数组合与AND指令相同。</p>
<p>在发现操作数中单个位是否置位时，TEST指令非常有用。</p>
<h5 id="多位测试"><a href="#多位测试" class="headerlink" title="多位测试"></a>多位测试</h5><p>这个例子里，提到了<strong>位掩码</strong></p>
<h4 id="6-2-8-CMP指令"><a href="#6-2-8-CMP指令" class="headerlink" title="6.2.8 CMP指令"></a>6.2.8 CMP指令</h4><p>X86汇编语言用CMP指令比较整数。字符代码也是整数，因此可以用CMP指令。浮点数需要特殊的比较指令，相关内容将在第12章介绍。<br><strong>CMP(比较)指令执行从目的操作数中减去源操作数的隐含减法操作，并且不修改任何操作数</strong>：</p>
<p>无符号数和有符号数在该指令下标志位结果不同</p>
<h4 id="6-2-9-置位和清除单个CPU标志位"><a href="#6-2-9-置位和清除单个CPU标志位" class="headerlink" title="6.2.9 置位和清除单个CPU标志位"></a>6.2.9 置位和清除单个CPU标志位</h4><p>涉及细节操作，看电子书的P176页，纸质的P155</p>
<h4 id="6-2-10-64位模式下的布尔指令"><a href="#6-2-10-64位模式下的布尔指令" class="headerlink" title="6.2.10 64位模式下的布尔指令"></a>6.2.10 64位模式下的布尔指令</h4><h3 id="6-3-条件跳转"><a href="#6-3-条件跳转" class="headerlink" title="6.3 条件跳转"></a>6.3 条件跳转</h3><h4 id="6-3-1-条件结构"><a href="#6-3-1-条件结构" class="headerlink" title="6.3.1 条件结构"></a>6.3.1 条件结构</h4><p>执行一个条件语句需要两个步骤：</p>
<p>第一步，用CMP、AND或SUB操作来<strong>修改CPU状态标志位</strong>；</p>
<p>第二步，用条件跳转指令来测试标志位，并产生一个到新地址的分支。</p>
<p>即：根据状态标志位决定跳转</p>
<h4 id="6-3-2-Jcond指令"><a href="#6-3-2-Jcond指令" class="headerlink" title="6.3.2 Jcond指令"></a>6.3.2 Jcond指令</h4><p>cond是指确定一个或多个标志位状态的标志位条件。下面是基于进位和零标志位的例子</p>
<p>jz，为0跳转（零标志位1）</p>
<p>jnz，非0跳转（零标志位清0）</p>
<p>jc，进位跳转（进位标志位1）</p>
<p>jnc，无进位跳转（进位标志位清0）</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">cmp eax，5</span><br><span class="line">je L1;如果相等则跳转（euqall）</span><br><span class="line">jl L1;小于则跳转</span><br><span class="line">jg L1;大于则跳转</span><br><span class="line"></span><br></pre></td></tr></table></figure>



<h4 id="6-3-3-条件跳转指令类型"><a href="#6-3-3-条件跳转指令类型" class="headerlink" title="6.3.3 条件跳转指令类型"></a>6.3.3 条件跳转指令类型</h4><p><img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210208170631447.png" alt="image-20210208170631447"></p>
<p><img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210208170654346.png" alt="image-20210208170654346"></p>
<p><img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210208171125093.png" alt="image-20210208171125093"></p>
<p><img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210208171207038.png" alt="image-20210208171207038"></p>
<h4 id="6-3-4-条件跳转应用"><a href="#6-3-4-条件跳转应用" class="headerlink" title="6.3.4 条件跳转应用"></a>6.3.4 条件跳转应用</h4><h5 id="测试状态位"><a href="#测试状态位" class="headerlink" title="测试状态位"></a>测试状态位</h5><h5 id="两个数中的较大数"><a href="#两个数中的较大数" class="headerlink" title="两个数中的较大数"></a>两个数中的较大数</h5><h5 id="三个数的最小数"><a href="#三个数的最小数" class="headerlink" title="三个数的最小数"></a>三个数的最小数</h5><h3 id="6-4-条件循环指令"><a href="#6-4-条件循环指令" class="headerlink" title="6.4 条件循环指令"></a>6.4 条件循环指令</h3><h5 id="6-4-1-LOOPZ和LOOPE指令"><a href="#6-4-1-LOOPZ和LOOPE指令" class="headerlink" title="6.4.1 LOOPZ和LOOPE指令"></a>6.4.1 LOOPZ和LOOPE指令</h5><p>LOOPZ（为0跳转）</p>
<p>LOOPE（相等跳转）</p>
<h5 id="6-4-2-LOOPNZ和LOOPNE指令"><a href="#6-4-2-LOOPNZ和LOOPNE指令" class="headerlink" title="6.4.2 LOOPNZ和LOOPNE指令"></a>6.4.2 LOOPNZ和LOOPNE指令</h5><p>LOOPZ（非0跳转）</p>
<p>LOOPE（不等跳转）</p>
<p>这里会用到pushfd和popfd,因为add可能修改标志位</p>
<h3 id="6-5-条件结构"><a href="#6-5-条件结构" class="headerlink" title="6.5 条件结构"></a>6.5 条件结构</h3><p>该部分讨论高级语言的条件结构如何转化为低级语言</p>
<h4 id="6-5-1-块结构的IF语句"><a href="#6-5-1-块结构的IF语句" class="headerlink" title="6.5.1 块结构的IF语句"></a>6.5.1 块结构的IF语句</h4><p><strong>相同的高级语言在汇编语言中的实现不一定相同</strong></p>
<p>方案1是条件跳转+CMP指令</p>
<p>方案2是JE实现&#x3D;&#x3D;（没有方案1来的紧凑）</p>
<h5 id="白盒测试"><a href="#白盒测试" class="headerlink" title="白盒测试"></a>白盒测试</h5><p>复杂条件语句可能有多个执行路径，这使得它们难以进行调试检查（查看代码）。程序员经常使用的技术称为白盒测试，用来验证子程序的输入和相应的输出。白盒测试需要源代码，并对输入变量进行不同的赋值。对每个输入组合，要手动跟踪源代码，验证其执行路径和子程序产生的输出（主要面对大量if-else嵌套）</p>
<h4 id="6-5-2-复合表达式"><a href="#6-5-2-复合表达式" class="headerlink" title="6.5.2 复合表达式"></a>6.5.2 复合表达式</h4><p>从电子PDF P188页开始</p>
<h4 id="6-5-3-while循环"><a href="#6-5-3-while循环" class="headerlink" title="6.5.3  while循环"></a>6.5.3  while循环</h4><h4 id="6-5-4-表驱动选择"><a href="#6-5-4-表驱动选择" class="headerlink" title="6.5.4 表驱动选择"></a>6.5.4 表驱动选择</h4><p>用查表替代多路选择的方法（即switch case）</p>
<p>表驱动选择有一些初始化开销，但是它能减少编写的代码总量。一个表就可以处理大量的比较，并且与一长串的比较、跳转和CALL指令序列相比，它更加容易修改。甚至在运行时，表还可以重新配置</p>
<h3 id="6-6-应用：有限状态机（FSM）"><a href="#6-6-应用：有限状态机（FSM）" class="headerlink" title="6.6 应用：有限状态机（FSM）"></a>6.6 应用：有限状态机（FSM）</h3><p>有限状态机（FSM）指一种被称为<strong>有向图</strong>的更一般结构特例</p>
<h5 id="6-6-1-验证输入字符串"><a href="#6-6-1-验证输入字符串" class="headerlink" title="6.6.1 验证输入字符串"></a>6.6.1 验证输入字符串</h5><p>相当多的细节，从电子PDF193开始</p>
<h5 id="6-6-2验证有符号整数"><a href="#6-6-2验证有符号整数" class="headerlink" title="6.6.2验证有符号整数"></a>6.6.2验证有符号整数</h5><h3 id="6-7-条件控制流伪指令"><a href="#6-7-条件控制流伪指令" class="headerlink" title="6.7 条件控制流伪指令"></a>6.7 条件控制流伪指令</h3><p>32位模式下，MASM包含了一些高级条件控制流伪指令（conditional control flowdirectives)，这有助于简化编写条件语句。<strong>遗憾的是，这些伪指令不能用于64位模式</strong>（简化汇编的开发流程）</p>
<p><img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210208180321748.png" alt="image-20210208180321748"></p>
<p><img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210208180341845.png" alt="image-20210208180341845"></p>
<h4 id="6-7-1-新建IF语句"><a href="#6-7-1-新建IF语句" class="headerlink" title="6.7.1 新建IF语句"></a>6.7.1 新建IF语句</h4><p>在调试的时候，在伪指令上右键到diassembly，就可以看到伪代码实现过程</p>
<h4 id="6-7-2-有符号数和无符号数的比较"><a href="#6-7-2-有符号数和无符号数的比较" class="headerlink" title="6.7.2 有符号数和无符号数的比较"></a>6.7.2 有符号数和无符号数的比较</h4><p>基于伪代码的汇编</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">array dword 5</span><br><span class="line">result dword ?</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov eax,6</span><br><span class="line">	.if eax&gt;val1</span><br><span class="line">	mov result,1</span><br><span class="line">	.endif</span><br><span class="line"></span><br><span class="line">	invoke ExitProcess,0</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>汇编器用JBE（无符号跳转）指令对其进行扩展</p>
<h5 id=""><a href="#" class="headerlink" title=""></a></h5><h5 id="有符号比较"><a href="#有符号比较" class="headerlink" title="有符号比较"></a>有符号比较</h5><p>汇编器用JLE指令生成代码，即基于有符号比较的跳转</p>
<h5 id="寄存器比较"><a href="#寄存器比较" class="headerlink" title="寄存器比较"></a>寄存器比较</h5><p>下面生成的代码表示汇编器将其默认为无符号数比较（注意使用的是JBE指令）：</p>
<h4 id="6-7-3-复合表达式"><a href="#6-7-3-复合表达式" class="headerlink" title="6.7.3 复合表达式"></a>6.7.3 复合表达式</h4><h4 id="6-7-4-用-REPEAT和-WHILE创建循环"><a href="#6-7-4-用-REPEAT和-WHILE创建循环" class="headerlink" title="6.7.4 用.REPEAT和.WHILE创建循环"></a>6.7.4 用.REPEAT和.WHILE创建循环</h4><p>repeat对应while……if</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">.repeat</span><br><span class="line">	statements</span><br><span class="line">.until condition</span><br></pre></td></tr></table></figure>



<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">.while condition</span><br><span class="line">	statement</span><br><span class="line">.ENDW</span><br></pre></td></tr></table></figure>



<h4 id="6-8-本章小结"><a href="#6-8-本章小结" class="headerlink" title="6.8 本章小结"></a>6.8 本章小结</h4><p>TEST指令对目的操作数执行隐含的AND操作，并正确地设置标志位。目的操作数不变。<br>NOT指令将目的操作数的每一位取反。</p>
<p>表6-4列出了基于无符号数比较的条件跳转，例如：JA（大于则跳转）、JB（小于则跳转）和JAE（大于等于则跳转）。</p>
<pre><code>32位模式下，若零标志位等于1，且ECX大于零，则LOOPZ(LOOPE）指令重复循环。
若零标志位等于0，且ECX大于零，则LOOPNZ（LOOPNE)指令重复循环。在64位模式下，LOOPZ和LOOPNZ指令使用的是RCX寄存器。
</code></pre>
<p>流程图是用视图展示程序逻辑的一种有效工具。利用流程图作模型，可以很容易地编写汇编语言代码。给流程图中每一个符号都赋予一个标号，并在汇编源代码中使用同样的标号是很有帮助的。</p>
<h2 id="7-整数运算"><a href="#7-整数运算" class="headerlink" title="7 整数运算"></a>7 整数运算</h2><p>本章将介绍汇编语言最大的优势之一：基本的二进制移位和循环移位技术。</p>
<h3 id="7-1-移位和循环移位指令"><a href="#7-1-移位和循环移位指令" class="headerlink" title="7.1 移位和循环移位指令"></a>7.1 移位和循环移位指令</h3><p>bit shifting(位移动)</p>
<p><img src="C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210208183955337.png" alt="image-20210208183955337"></p>
<p>这些指令会影响<strong>溢出标志位</strong>和<strong>进位标志位</strong></p>
<p>左移和算数左移为什么不一样？</p>
<h4 id="7-1-1-逻辑以为和算数移位"><a href="#7-1-1-逻辑以为和算数移位" class="headerlink" title="7.1.1 逻辑以为和算数移位"></a>7.1.1 逻辑以为和算数移位</h4><p>第一种是逻辑移位（logic shift)，空出来的位用0填充</p>
<p>第二种是算术移位（arithmetic shift)，空出来的位用<strong>原数据</strong>的符号位填充</p>
<h4 id="7-1-2-SHL指令"><a href="#7-1-2-SHL指令" class="headerlink" title="7.1.2 SHL指令"></a>7.1.2 SHL指令</h4><p>SHL(左移）指令使目的操作数逻辑左移一位，最低位用0填充</p>
<p>位元乘法</p>
<h4 id="7-1-3-SHR指令"><a href="#7-1-3-SHR指令" class="headerlink" title="7.1.3 SHR指令"></a>7.1.3 SHR指令</h4><p>位元除法</p>
<h4 id="7-1-4-SAL和SAR指令"><a href="#7-1-4-SAL和SAR指令" class="headerlink" title="7.1.4 SAL和SAR指令"></a>7.1.4 SAL和SAR指令</h4><p>SAL(算术左移）指令的操作与SHL指令一样。每次移动时，SAL都将目的操作数中的每一位移动到下一个最高位上。最低位用0填充；最高位移入进位标志位，该标志位原来的值被丢弃</p>
<p>适用于<strong>有符号数除法</strong></p>
<h5 id="AX符号扩展到EAX"><a href="#AX符号扩展到EAX" class="headerlink" title="AX符号扩展到EAX"></a>AX符号扩展到EAX</h5><p>设AX中为有符号数，现将其符号位扩展到EAX。首先把EAX左移16位，再将其算术右移16位</p>
<h4 id="7-1-5-ROL指令"><a href="#7-1-5-ROL指令" class="headerlink" title="7.1.5 ROL指令"></a>7.1.5 ROL指令</h4><p>以循环方式来移位即为位元循环（Bitwise Rotation)。一些操作中，从数的一端移出的位立即复制到该数的另一端。还有一种类型则是把进位标志位当作移动位的中间点。</p>
<p>位循环不会丢弃位。从数的一端循环出去的位会出现在该数的另一端。</p>
<p>进位标志位保存的是最后循环移出MSB的位</p>
<h4 id="7-1-6-ROR指令"><a href="#7-1-6-ROR指令" class="headerlink" title="7.1.6 ROR指令"></a>7.1.6 ROR指令</h4><p>进位标志位保存的是最后循环移出LSB的位</p>
<h4 id="7-1-7-RCL和RCR指令"><a href="#7-1-7-RCL和RCR指令" class="headerlink" title="7.1.7 RCL和RCR指令"></a>7.1.7 RCL和RCR指令</h4><p>RCL（带进位循环左移）指令把每一位都向左移，进位标志位复制到LSB，而MSB复制到进位标志位</p>
<p>RCR指令RCR（带进位循环右移)指令把每一位都向右移，进位标志位复制到MSB而LSB复制到进位标志位</p>
<h4 id="7-1-8-有符号数溢出"><a href="#7-1-8-有符号数溢出" class="headerlink" title="7.1.8 有符号数溢出"></a>7.1.8 有符号数溢出</h4><p>如果有符号数循环移动一位生成的结果超过了目的操作数的有符号数范围，则溢出标志位置1。换句话说，<strong>即该数的符号位取反</strong>。</p>
<h4 id="7-1-9-SHLD-x2F-SHRD-指令"><a href="#7-1-9-SHLD-x2F-SHRD-指令" class="headerlink" title="7.1.9 SHLD&#x2F;SHRD 指令"></a>7.1.9 SHLD&#x2F;SHRD 指令</h4><p>SHLD(双精度左移）指令将目的操作数向左移动指定位数。移动形成的空位由<strong>源操作数（？）</strong>的高位填充。源操作数不变，<strong>但是符号标志位、零标志位、辅助进位标志位、奇偶标志位和进位标志位会受影响</strong></p>
<p>还没有熟练掌握</p>
<h3 id="7-2-移位和循环的应用"><a href="#7-2-移位和循环的应用" class="headerlink" title="7.2 移位和循环的应用"></a>7.2 移位和循环的应用</h3><h4 id="7-2-1-多个双字的移位"><a href="#7-2-1-多个双字的移位" class="headerlink" title="7.2.1 多个双字的移位"></a>7.2.1 多个双字的移位</h4><p>小端顺序：将数组的最低字节存放到它的起始地址</p>
<p><strong>小端字节序指低字节数据存放在内存低地址处，高字节数据存放在内存高地址处</strong></p>
<p>具体案例放下面</p>
<p><a target="_blank" rel="noopener external nofollow noreferrer" href="http://www.cppblog.com/aaxron/archive/2011/02/28/140786.html">http://www.cppblog.com/aaxron/archive/2011/02/28/140786.html</a></p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;assert.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line">        <span class="type">short</span> test;</span><br><span class="line">        FILE* fp;</span><br><span class="line">         </span><br><span class="line">        test = <span class="number">0x3132</span>; <span class="comment">/* (31ASIIC码的&#x27;1&#x27;, 32ASIIC码的&#x27;2&#x27;) */</span></span><br><span class="line">        <span class="keyword">if</span> ((fp = fopen(<span class="string">&quot;c:\\test.txt&quot;</span>, <span class="string">&quot;wb&quot;</span>)) == <span class="literal">NULL</span>)</span><br><span class="line">              assert(<span class="number">0</span>);</span><br><span class="line">        fwrite(&amp;test, <span class="keyword">sizeof</span>(<span class="type">short</span>), <span class="number">1</span>, fp);</span><br><span class="line">        fclose(fp);</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>而书本给的操作没有看懂，感觉很迷</p>
<h4 id="7-2-2-二进制乘法"><a href="#7-2-2-二进制乘法" class="headerlink" title="7.2.2 二进制乘法"></a>7.2.2 二进制乘法</h4><p>快速幂</p>
<p>部分情况下代替MUL</p>
<h4 id="7-2-3-显示二进制位"><a href="#7-2-3-显示二进制位" class="headerlink" title="7.2.3 显示二进制位"></a>7.2.3 显示二进制位</h4><p>将二进制整数转换为ASCIⅡ码的位串，并显示出来是一种常见的编程任务。SHL指令适用于这个要求，因为每次操作数左移时，它都会把操作数的最高位复制到进位标志位</p>
<p>运行时报错（2021.2.8）</p>
<p>（先保留，留到以后微机接口看）</p>
<h4 id="7-2-4-提取文件日期字段"><a href="#7-2-4-提取文件日期字段" class="headerlink" title="7.2.4 提取文件日期字段"></a>7.2.4 提取文件日期字段</h4><p>位0<del>位4表示的是131内的日期；位5</del>位8表示的是月份；位9~位15表示的是年份</p>
<p>在这种情况下，可以通过位遮蔽和右移得到想要的数据</p>
<h3 id="7-3-乘法和除法指令"><a href="#7-3-乘法和除法指令" class="headerlink" title="7.3 乘法和除法指令"></a>7.3 乘法和除法指令</h3><h4 id="7-3-1-MUL指令"><a href="#7-3-1-MUL指令" class="headerlink" title="7.3.1 MUL指令"></a>7.3.1 MUL指令</h4><p>MUL无符号数乘法，可执行8，16，32位的乘法</p>
<p>默认<strong>被乘数</strong>是AL，AX，EAX</p>
<p>所以MUL的参数只有一个</p>
<p><strong>乘数和被乘数的大小必须保持一致，乘积的大小则是它们的一倍</strong></p>
<p>如果出现溢出，16位的高位会放在DX，32位的高位会放在EDX，64位会在RDX</p>
<h4 id="7-3-2-IMUL指令"><a href="#7-3-2-IMUL指令" class="headerlink" title="7.3.2 IMUL指令"></a>7.3.2 IMUL指令</h4><p>IMUL（有符号数乘法）</p>
<p>该指令支持<strong>单操作数，双操作数，三操作数</strong></p>
<p>单操作数类似MUL</p>
<p>双操作数格式会按照目的操作数的大小来截取乘积</p>
<p>因此，在执行了有两个操作数的IMUL操作后，<strong>必须检查这些标志位（进位或溢出）中的一个</strong>。</p>
<p>三操作数格式</p>
<p>32位模式下的三操作数格式<strong>将乘积保存在第一个操作数</strong>中。第二个操作数可以是16位寄存器或内存操作数，它与第三个操作数相乘，该操作数是一个8位或16位立即数</p>
<p>双操作数和三操作数IMUL指令的目的操作数大小与乘数大小相同。因此，有可能发生有符号溢出。执行这些类型的IMUL指令后，总要检查溢出标志位</p>
<h4 id="7-3-3-测量程序运行的时间"><a href="#7-3-3-测量程序运行的时间" class="headerlink" title="7.3.3 测量程序运行的时间"></a>7.3.3 测量程序运行的时间</h4><p>Microsoft WindowsAPI为此提供了必要的工具，Irvine32库中的GetMseconds过程可使其变得更加方便使用</p>
<p>处理器可以通过位移法加快MUL计算</p>
<h4 id="7-3-4-DIV指令"><a href="#7-3-4-DIV指令" class="headerlink" title="7.3.4 DIV指令"></a>7.3.4 DIV指令</h4><p>DIV（无符号除法）</p>
<p>商放在低位（AL），余数放在高位（AH）</p>
<h4 id="7-3-5-有符号数除法"><a href="#7-3-5-有符号数除法" class="headerlink" title="7.3.5 有符号数除法"></a>7.3.5 有符号数除法</h4><p>有符号除法几乎与无符号除法相同，只有一个重要的区别：<strong>在执行除法之前，必须对被除数进行符号扩展</strong>。</p>
<p>符号扩展 是指将一个数的最高位复制到包含该数的变量或寄存器的所有高位中</p>
<p>一个例子</p>
<p>-101在byte计算器中是9Bh,可在word计算器里，155是9B（无符号的，由此表明<strong>符号扩展</strong>的必要性）</p>
<p>而解决该问题的正确方法是使用CWD（字转双字)指令，在进行除法之前在DX：AX中对AX进行符号扩展</p>
<h5 id="1-符号扩展指令（CBW、CWD、CDQ）"><a href="#1-符号扩展指令（CBW、CWD、CDQ）" class="headerlink" title="1.符号扩展指令（CBW、CWD、CDQ）"></a>1.符号扩展指令（CBW、CWD、CDQ）</h5><p>Intel提供了三种符号扩展指令：CBW（字节转字）、CWD（字转双字）和CDQ（双字转四字）</p>
<h5 id="2-IDIV指令"><a href="#2-IDIV指令" class="headerlink" title="2.IDIV指令"></a>2.IDIV指令</h5><p>IDIV(有符号除法)指令执行有符号整数除法，其操作数与DIV指令相同。执行8位除法之前，被除数（AX）必须完成符号扩展。余数的符号总是与被除数相同。</p>
<p><strong>执行DIV和IDIV后，所有算术运算状态标志位的值都不确定</strong></p>
<h5 id="3-除法溢出"><a href="#3-除法溢出" class="headerlink" title="3.除法溢出"></a>3.除法溢出</h5><p>如果除法操作数生成的商不适合目的操作数，则产生除法溢出（divide overflow)。这将导致处理器异常并暂停执行当前程序。</p>
<p>对此有个建议：使用<strong>32位除数</strong>和<strong>64位被除数</strong>来减少出现除法溢出条件的可能性</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">cmp b1,0 ；检查除数</span><br><span class="line">je NoDividezero 为零？显示错误</span><br></pre></td></tr></table></figure>



<h4 id="7-3-6-实现算数表达式"><a href="#7-3-6-实现算数表达式" class="headerlink" title="7.3.6 实现算数表达式"></a>7.3.6 实现算数表达式</h4><p>看C++的编译代码，看看能不能从中有所启发</p>
<h3 id="7-4-扩展加减法"><a href="#7-4-扩展加减法" class="headerlink" title="7.4 扩展加减法"></a>7.4 扩展加减法</h3><h4 id="7-4-1-ADC指令"><a href="#7-4-1-ADC指令" class="headerlink" title="7.4.1 ADC指令"></a>7.4.1 ADC指令</h4><p>ADC（带进位加法）</p>
<h4 id="7-4-2-扩展整数加法示例"><a href="#7-4-2-扩展整数加法示例" class="headerlink" title="7.4.2 扩展整数加法示例"></a>7.4.2 扩展整数加法示例</h4><h4 id="7-4-3-SBB指令"><a href="#7-4-3-SBB指令" class="headerlink" title="7.4.3 SBB指令"></a>7.4.3 SBB指令</h4><p>SBB(带借位减法)指令从目的操作数中减去源操作数和进位标志位的值。允许使用的操作数与ADC指令相同。</p>
<h3 id="7-5-ASCII和非压缩十进制运算"><a href="#7-5-ASCII和非压缩十进制运算" class="headerlink" title="7.5 ASCII和非压缩十进制运算"></a>7.5 ASCII和非压缩十进制运算</h3><p><strong>7.5节讨论的指令只能用于32位模式编程</strong></p>
<p>ASCII加减法运行操作数为ASCII格式或非压缩十进制格式，但是乘除法只能使用非压缩十进制数</p>
<p>  尽管ASCII运算执行速度比二进制运算要慢很多，但是它有两个明显的优点：<br>    ·不必在执行运算之前转换串格式。<br>    ·使用假设的十进制小数点，使得实数操作不会出现浮点运算的舍入误差的危险。</p>
<h4 id="7-5-1-AAA指令"><a href="#7-5-1-AAA指令" class="headerlink" title="7.5.1 AAA指令"></a>7.5.1 AAA指令</h4><p>在32位模式下，AAA（<strong>加法后的ASCII调整</strong>）指令调整ADD或ADC指令的二进制运算结果。设两个ASCII数字相加，其二进制结果存放在AL中，则AAA将AL转换为两个非压缩十进制数字存入AH和AL。一旦成为非压缩格式，通过将AH和AL与30h进OR运算，很容易就能把它们转换为ASCIT码。</p>
<p>计算带有小数点的十进制数时，这种做法比较好</p>
<h4 id="7-5-2-AAS指令"><a href="#7-5-2-AAS指令" class="headerlink" title="7.5.2 AAS指令"></a>7.5.2 AAS指令</h4><p>32位模式下，AAS（减法后的ASCII调整）指令紧随SUB或SBB指令之后，这两条指令执行两个非压缩十进制数的减法，并将结果保存到AL中。AAS指令将AL转换为ASCII码的数字形式。只有减法结果为负时，调整才是必需的。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">val1 byte &#x27;8&#x27;</span><br><span class="line">val2 byte &#x27;9&#x27;</span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line">	mov	ah,0	</span><br><span class="line">	mov al,val1</span><br><span class="line">	sub al,val2</span><br><span class="line">	aas</span><br><span class="line">	pushf</span><br><span class="line">	or al,30h</span><br><span class="line">	popf</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h4 id="7-5-3-AAM指令"><a href="#7-5-3-AAM指令" class="headerlink" title="7.5.3 AAM指令"></a>7.5.3 AAM指令</h4><p>32位模式下，MUL执行非压缩十进制乘法，AAM（乘法后的ASCIⅡ调整)指令转换由其产生的二进制乘积。<strong>乘法只能使用非压缩十进制数</strong>。</p>
<p>表现形式是16进制（结果带有h），但是出来的却是十进制</p>
<h4 id="7-5-4-AAD指令"><a href="#7-5-4-AAD指令" class="headerlink" title="7.5.4 AAD指令"></a>7.5.4 AAD指令</h4><p>32位模式下，AAD（除法之前的ASCII调整)指令将AX中的非压缩十进制被除数转换为二进制，为执行DIV指令做准备。</p>
<h3 id="7-6-压缩十进制计算"><a href="#7-6-压缩十进制计算" class="headerlink" title="7.6 压缩十进制计算"></a>7.6 压缩十进制计算</h3><p>（7.6节讨论的指令仅用于32位编程模式)</p>
<p>压缩十进制数的<strong>每个字节存放两个十进制数字</strong>，每个数字用4位表示。<strong>如果数字个数为奇数</strong>，则最高的半字节用零填充。</p>
<p>DAA(加法后的十进制调整）和DAS（减法后的十进制调整）这两条指令调整压缩十进制数加减法的结果。</p>
<p>可惜的是，<strong>目前还没有与乘除法有关的相似指令</strong>。在这些情况下，相乘或相除的数必须是非压缩的，执行后再压缩。</p>
<h4 id="7-6-1-DAA指令"><a href="#7-6-1-DAA指令" class="headerlink" title="7.6.1 DAA指令"></a>7.6.1 DAA指令</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mov al,35h </span><br><span class="line">add al,48h ；AL=7Dh </span><br><span class="line">daa			；AL=83h（调整后的结果）</span><br></pre></td></tr></table></figure>



<h4 id="7-6-2-DAS指令"><a href="#7-6-2-DAS指令" class="headerlink" title="7.6.2 DAS指令"></a>7.6.2 DAS指令</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mov bl,48h </span><br><span class="line">mov al,85h </span><br><span class="line">sub al,b1；AL=3Dh </span><br><span class="line">das；AL=37h（调整后的结果）</span><br></pre></td></tr></table></figure>



<h2 id="8-高级过程"><a href="#8-高级过程" class="headerlink" title="8 高级过程"></a>8 高级过程</h2><p>本章学习的详细内容与C++和Java知识相关，将展示：</p>
<p><strong>如何以数值或引用的形式来传递参数；如何定义和撤销局部变量；以及如何实现递归。</strong></p>
<p>在本章结束时，将解释MASM使用的不同的内存模式和语言标识符。参数既可以用寄存器传递也可以用堆栈传递。</p>
<p>编程语言用不同的术语来指代子程序。例如，在C和C++中，子程序被称为函数（functions)。在Java中，被称为方法（methods)。在MASM中，则被称为过程（procedures)。本章目的是说明典型子程序调用的底层实现，就像它们在C和C++中展现的那样。在本章开始提到一般原则时，将使用泛称：子程序。而在提到具体汇编语言代码示例时，通常会使用术语过程来指代子程序。</p>
<h3 id="8-2-堆栈帧"><a href="#8-2-堆栈帧" class="headerlink" title="8.2 堆栈帧"></a>8.2 堆栈帧</h3><h4 id="8-2-1-堆栈参数"><a href="#8-2-1-堆栈参数" class="headerlink" title="8.2.1 堆栈参数"></a>8.2.1 堆栈参数</h4><p>堆栈帧（stack frame)（或活动记录（activation record))是一块<strong>堆栈保留区域</strong>，用于存放被传递的实际参数、子程序的返回值、局部变量以及被保存的寄存器</p>
<p>几乎所有高级语言都会用到他们</p>
<p>子程序调用时，有两种常见类型的参数会入栈：<br>·值参数（变量和常量的值）</p>
<p>·引用参数（变量的地址）</p>
<h5 id="值传递"><a href="#值传递" class="headerlink" title="值传递"></a>值传递</h5><p>传递的是变量的副本</p>
<h5 id="引用传递"><a href="#引用传递" class="headerlink" title="引用传递"></a>引用传递</h5><p>传递的是变量的地址（offset）</p>
<h4 id="8-2-3-访问堆栈参数"><a href="#8-2-3-访问堆栈参数" class="headerlink" title="8.2.3 访问堆栈参数"></a>8.2.3 访问堆栈参数</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">push ebp</span><br><span class="line">mov ebp,esp ;做到这一步，EBP成为了函数的基址指针</span><br></pre></td></tr></table></figure>

<h5 id="1-显式的堆栈参数"><a href="#1-显式的堆栈参数" class="headerlink" title="1.显式的堆栈参数"></a>1.显式的堆栈参数</h5><p>若堆栈参数的引用表达式形如[ebp+8]，则称它们为显式的堆栈参数（explicit stackparameters)。这个名称的含义是：汇编代码显式地说明了参数的偏移量是一个常数。</p>
<h5 id="2-清除堆栈"><a href="#2-清除堆栈" class="headerlink" title="2.清除堆栈"></a>2.清除堆栈</h5><p>子程序返回时，必须<strong>将参数从堆栈中删除</strong>。否则将<strong>导致内存泄露</strong>，堆栈就会被破坏。</p>
<h4 id="8-2-4-32位调用规范"><a href="#8-2-4-32位调用规范" class="headerlink" title="8.2.4 32位调用规范"></a>8.2.4 32位调用规范</h4><p>本节将给出Windows环境中两种最常用的32位编程调用规范。</p>
<p>首先是C语言发布的C调用规范，该语言用于Unix和Windows。</p>
<p>然后是STDCALL调用规范，它描述了调用Windows API函数的协议。</p>
<p>这两种规范都很重要，因为在C和C++程序中会调用汇编函数，同时汇编语言程序也会调用大量的WindowsAPI函数。</p>
<h5 id="C调用规范"><a href="#C调用规范" class="headerlink" title="C调用规范"></a>C调用规范</h5><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">AddTWO(A,B);</span><br></pre></td></tr></table></figure>

<p>B先入栈，然后A再入栈</p>
<p>C调用规范用一种简单的方法解决了清除运行时堆栈的问题：程序调用子程序时，在CALL指令的后面紧跟一条语句使堆栈指针（ESP)<strong>加上一个数</strong>，该<strong>数的值即为子程序参数所占堆栈空间的总和</strong>。下面的例子在执行CALL指令之前，将两个参数（5和6）入栈</p>
<h5 id="STDCALL调用规范"><a href="#STDCALL调用规范" class="headerlink" title="STDCALL调用规范"></a>STDCALL调用规范</h5><p>如下所示的AddTwo过程给<strong>RET指令添加了一个整数参数</strong>，这使得程序在返回到调用过程时，ESP会加上数值8。<strong>这个添加的整数必须与被调用过程参数占用的堆栈空间字节数相等</strong></p>
<h4 id="8-2-5-局部变量"><a href="#8-2-5-局部变量" class="headerlink" title="8.2.5 局部变量"></a>8.2.5 局部变量</h4><p>局部变量创建于运行时堆栈，<strong>通常位于基址指针（EBP）之下</strong>。尽管不能在汇编时给它们分配默认值，<strong>但是能在运行时初始化它们</strong>。可以使用与C和C++相同的方法在汇编语言中新建局部变量。</p>
<p><strong>经典案例</strong></p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">MySub PROC </span><br><span class="line"></span><br><span class="line">push ebp </span><br><span class="line">mov ebp，esp </span><br><span class="line"></span><br><span class="line">sub esp,8；创建局部变量 </span><br><span class="line">moV DWORD PTR [ebp-4],10；x </span><br><span class="line">mov DWORD PTR [ebp-8],20;Y </span><br><span class="line"></span><br><span class="line">mov esp,ebp</span><br><span class="line">pop ebp </span><br><span class="line"></span><br><span class="line">ret </span><br><span class="line">MySub ENDP</span><br></pre></td></tr></table></figure>

<p>可以使用局部变量使用使程序易读</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">X_local EQU DWORD PTR [ebp-4] </span><br><span class="line">Y_local EQU DWORD PTR [ebp-8]</span><br></pre></td></tr></table></figure>

<p>两个函数用了两个堆栈（每个函数都有自己的栈空间）</p>
<p>使用Move指令的原因是，那两个数还未赋值，最后做到的效果跟铺设差不多</p>
<h4 id="8-2-6-引用参数"><a href="#8-2-6-引用参数" class="headerlink" title="8.2.6 引用参数"></a>8.2.6 引用参数</h4><p>引用参数通常是由过程用基址一偏移量寻址（从EBP）方式进行访问。由于<strong>每个引用参数都是一个指针</strong>，因此，常常作为一个间接操作数放在寄存器中</p>
<p>数组偏移量——数组指针地址</p>
<p>数组长度——数组大小</p>
<p>最后通过访问堆栈的形式访问参数</p>
<h4 id="8-2-7-LEA指令"><a href="#8-2-7-LEA指令" class="headerlink" title="8.2.7 LEA指令"></a>8.2.7 LEA指令</h4><p>LEA指令返回间接操作数的地址</p>
<p>会在运行时<strong>计算</strong>这些操作数的偏移量（用于不确定数组大小的情况）</p>
<p>面对这样的数组时，offset没法使用，只能用offset</p>
<p><strong>虽然数组只有30个字节，但是ESP还是递减了32以对齐双字边界</strong></p>
<h4 id="8-2-8-ENTER和LEAVE指令"><a href="#8-2-8-ENTER和LEAVE指令" class="headerlink" title="8.2.8 ENTER和LEAVE指令"></a>8.2.8 ENTER和LEAVE指令</h4><p>ENTER指令为被调用过程自动创建堆栈帧。它为局部变量保留堆栈空间，把EBP入栈。具体来说，它执行三个操作：<br>·把EBP入栈（push ebp)</p>
<p>·把EBP设置为堆栈帧的基址（mov ebp，esp)</p>
<p>·为局部变量保留空间（sub esp，numbytes)ENTER有两个操作数：</p>
<p>第一个是常数，定义为局部变量保存的堆栈空间字节数；</p>
<p>第二个定义了过程的词法嵌套级。</p>
<p><strong>如果要使用ENTER指令，那么本书强烈建议在同一个过程的结尾处同时使用LEAVE指令。否则，为局部变量保留的堆栈空间就可能无法释放。这将会导致RET指令从堆栈中弹出错误的返回地址</strong></p>
<p>LEAVE指令LEAVE指令结束一个过程的堆栈帧。它反转了之前的ENTER指令操作：<br>恢复了过程被调用时ESP和EBP的值。</p>
<p>（没有参数）</p>
<h4 id="8-2-9-LOCAL伪指令"><a href="#8-2-9-LOCAL伪指令" class="headerlink" title="8.2.9 LOCAL伪指令"></a>8.2.9 LOCAL伪指令</h4><p>Microsoft创建LOCAL伪指令是作为ENTER指令的高级替补</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">.code</span><br><span class="line">MySub PROC </span><br><span class="line">	local num:byte</span><br><span class="line">	mov num,1</span><br><span class="line">	mov eax,1</span><br><span class="line">	ret</span><br><span class="line">MySub ENDP</span><br><span class="line"></span><br><span class="line">main PROC</span><br><span class="line">	mov eax,10</span><br><span class="line">	push eax</span><br><span class="line">	call MySub</span><br><span class="line">	pop eax</span><br><span class="line">	add eax,3</span><br><span class="line">main ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h4 id="8-2-10-Microsoft×64调用规范"><a href="#8-2-10-Microsoft×64调用规范" class="headerlink" title="8.2.10 Microsoft×64调用规范"></a>8.2.10 Microsoft×64调用规范</h4><h3 id="8-3-递归"><a href="#8-3-递归" class="headerlink" title="8.3 递归"></a>8.3 递归</h3><p>用寄存器的话，不许要局部变量</p>
<h5 id="无限递归"><a href="#无限递归" class="headerlink" title="无限递归"></a>无限递归</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Endless PROC </span><br><span class="line">mov edx,OFFSET endlessStr </span><br><span class="line">call WriteString </span><br><span class="line">call Endless </span><br><span class="line">ret；从不执行</span><br></pre></td></tr></table></figure>

<p>这个程序会在堆栈溢出时终止程序</p>
<h4 id="8-3-1-递归求和"><a href="#8-3-1-递归求和" class="headerlink" title="8.3.1 递归求和"></a>8.3.1 递归求和</h4><p>即使是一个简单的递归过程也会<strong>使用大量的堆栈空间</strong>。每次过程调用发生时最少占用4字节的堆栈空间，因为要把返回地址保存到堆栈。</p>
<p>calsum中的定义</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">CalcSum PROC</span><br><span class="line">; Calculates the sum of a list of integers</span><br><span class="line">; Receives: ECX = count</span><br><span class="line">; Returns: EAX = sum</span><br><span class="line">	cmp  ecx,0	; check counter value</span><br><span class="line">	jz   L2		; quit if zero</span><br><span class="line">	add  eax,ecx	; otherwise, add to sum</span><br><span class="line">	dec  ecx		; decrement counter</span><br><span class="line">	call CalcSum	; recursive call</span><br><span class="line">L2:	ret</span><br><span class="line">CalcSum ENDP</span><br></pre></td></tr></table></figure>



<h4 id="8-3-2-计算阶乘"><a href="#8-3-2-计算阶乘" class="headerlink" title="8.3.2 计算阶乘"></a>8.3.2 计算阶乘</h4><p>每一次都建立了新函数，所以每次堆栈的位置都不一样（但栈与栈之间都挨得很近）</p>
<figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">main PROC</span><br><span class="line">	push <span class="number">5</span>			; calculate <span class="number">5</span> factorial</span><br><span class="line">	call Factorial		; calculate <span class="title function_">factorial</span> <span class="params">(eax)</span></span><br><span class="line">main ENDP</span><br><span class="line"></span><br><span class="line">Factorial PROC</span><br><span class="line">	push ebp</span><br><span class="line">	mov  ebp,esp</span><br><span class="line">	mov  eax,[ebp+8]	; get n</span><br><span class="line">	cmp  eax,<span class="number">0</span>		; n &lt; <span class="number">0</span>?</span><br><span class="line">	ja   L1			; yes: <span class="keyword">continue</span></span><br><span class="line">	mov  eax,<span class="number">1</span>		; no: <span class="keyword">return</span> <span class="number">1</span></span><br><span class="line">	jmp  L2</span><br><span class="line"></span><br><span class="line">L1:	dec  eax</span><br><span class="line">	push eax			; Factorial(n<span class="number">-1</span>)</span><br><span class="line">	call Factorial</span><br><span class="line"></span><br><span class="line">; Instructions from this point on execute when each</span><br><span class="line">; recursive call returns.</span><br><span class="line"></span><br><span class="line">ReturnFact:</span><br><span class="line">	mov  ebx,[ebp+<span class="number">8</span>]   	; get n</span><br><span class="line">	mul  ebx          	; ax = ax * bx</span><br><span class="line"></span><br><span class="line">L2:	pop  ebp			; <span class="keyword">return</span> EAX</span><br><span class="line">	ret  <span class="number">4</span>			; clean up <span class="built_in">stack</span></span><br><span class="line">Factorial ENDP</span><br><span class="line">END main</span><br></pre></td></tr></table></figure>

<p>为什么L2包在RetutrnFact里面？原因是RetutrnFact里用到了L2退出堆栈</p>
<p>Returnfact在程序的内部以正常运算顺序内执行到</p>
<p>读者可能已经注意到之前的EAX，即第一次调用时分配给Factorial的值，被新值覆盖了。这说明了一个重要的事实：在过程进行递归调用时，应该小心注意哪些寄存器会被修改。如果需要保存这些寄存器的值，就需要在递归调用之前将其入栈，并在调用返回之后将其弹出堆栈。幸运的是，对Factorial过程而言，在递归调用之间保存EAX并不是必要的。</p>
<h3 id="8-4-INVOKE、ADDR、PROC和PROTO"><a href="#8-4-INVOKE、ADDR、PROC和PROTO" class="headerlink" title="8.4 INVOKE、ADDR、PROC和PROTO"></a>8.4 INVOKE、ADDR、PROC和PROTO</h3><p>在32位模式中，INVOKE、PROC和PROTO伪指令是过程定义和调用的强大工具。<br>ADDR运算符与这些伪指令一起使用，是定义过程参数的重要工具。</p>
<p>从教学的角度来看，它们的使用是有争议的，因为它们屏蔽了运行时堆栈的底层结构。因此，在使用这些伪指令之前，详细了解子程序调用的底层机制是非常明智的。</p>
<h4 id="8-4-1-INVOKE伪指令"><a href="#8-4-1-INVOKE伪指令" class="headerlink" title="8.4.1 INVOKE伪指令"></a>8.4.1 INVOKE伪指令</h4><p>INVOKE伪指令，只用于32位模式，将参数入栈（按照MODEL伪指令的语言说明符所指定的顺序）并调用过程。<strong>INVOKE是CALL指令一个方便的替代品</strong>，因为，它用一行代码就能传递多个参数。</p>
<p>将参数<strong>逆序压入堆栈</strong>当中</p>
<p>电子PDF P267页</p>
<p>覆盖EAX和EDX如果向过程传递的参数小于32位，那么在将参数入栈之前，INVOKE为了扩展参数常常会使得汇编器覆盖EAX和EDX的内容。有两种方法可以避免这种情况：<br>其一，传递给INVOKE的参数总是32位的；其二，在过程调用之前保存EAX和EDX，在讨程调用之后再恢复它们的值。</p>
<h4 id="8-4-2-ADDR伪指令"><a href="#8-4-2-ADDR伪指令" class="headerlink" title="8.4.2 ADDR伪指令"></a>8.4.2 ADDR伪指令</h4><p>ADDR运算符同样可用于32位模式，在使用INVOKE调用过程时，它可以<strong>传递指针参数</strong>。</p>
<p>必须是汇编常数且只能与INVOKE一起使用</p>
<h4 id="8-4-3-PROC伪指令"><a href="#8-4-3-PROC伪指令" class="headerlink" title="8.4.3 PROC伪指令"></a>8.4.3 PROC伪指令</h4><p>电子PDF P269页</p>
<h5 id="3-指定参数传递协议"><a href="#3-指定参数传递协议" class="headerlink" title="3.指定参数传递协议"></a>3.指定参数传递协议</h5><p>一个程序可以调用Irvine32链接库过程，反之，也可以包含能被C++程序调用的过程。<br>  为了提供这样的灵活性，PROC伪指令的属性域允许程序指定传递参数的语言规范，并且能覆盖.MODEL伪指令指定的默认语言规范。下例声明的过程采用了C调用规范：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Example1 PROCC，parm1：DWORD，parm2:DWORD</span><br></pre></td></tr></table></figure>

<h4 id="8-4-4-PROTO伪指令"><a href="#8-4-4-PROTO伪指令" class="headerlink" title="8.4.4 PROTO伪指令"></a>8.4.4 PROTO伪指令</h4><p>prototype</p>
<p>64位模式中，PROTO伪指令指定程序的外部过程</p>
<p>32位模式中，PROTO是一个更有用的工具，因为它可以包含<strong>过程参数列表</strong></p>
<p>相当于一个事先声明</p>
<h4 id="8-4-5-参数类别"><a href="#8-4-5-参数类别" class="headerlink" title="8.4.5 参数类别"></a>8.4.5 参数类别</h4><p>过程参数可分为输入类，输出类，输入输出类</p>
<p>电子PDF P274页</p>
<h4 id="8-4-7-调试提醒"><a href="#8-4-7-调试提醒" class="headerlink" title="8.4.7 调试提醒"></a>8.4.7 调试提醒</h4><h5 id="1-参数大小不匹配"><a href="#1-参数大小不匹配" class="headerlink" title="1.参数大小不匹配"></a>1.参数大小不匹配</h5><p>就是一个word应该是+4，+1的话就会出错</p>
<h5 id="2-传递错误类型的指针"><a href="#2-传递错误类型的指针" class="headerlink" title="2.传递错误类型的指针"></a>2.传递错误类型的指针</h5><p>指针类型不匹配</p>
<h5 id="3-传递立即数"><a href="#3-传递立即数" class="headerlink" title="3.传递立即数"></a>3.传递立即数</h5><p>如果过程有一个引用参数，就不要向其传递立即数参数，因为很可能把数据当成地址传递，从而出错</p>
<h4 id="8-4-8-WriteStackFrame过程"><a href="#8-4-8-WriteStackFrame过程" class="headerlink" title="8.4.8 WriteStackFrame过程"></a>8.4.8 WriteStackFrame过程</h4><p>Irvine32链接库有个很有用的过程WriteStackFrame，用于显示当前过程堆栈帧的内容，其中包括过程的堆栈参数、返回地址、局部变量和被保存的寄存器。</p>
<h3 id="8-5-创建多模块程序"><a href="#8-5-创建多模块程序" class="headerlink" title="8.5 创建多模块程序"></a>8.5 创建多模块程序</h3><p>把一个程序按模块（module)(汇编单位)分割。每个模块可以单独汇编，因此，对一个模块源代码的修改就只需要重汇编这个模块。链接器将所有汇编好的模块（OBJ文件）组合为一个可执行文件的速度是相当快的，链接大量目标模块比汇编同样数量的源代码文件花费的时间要少得多</p>
<p>新建多模块程序有两种常用方法：</p>
<p>其一是传统方法，使用EXTERN伪指令，基本上它在不同的x86汇编器之间都可以进行移植。</p>
<p>其二是使用Microsoft的高级伪指令INVOKE和PROTO，这能够简化过程调用，并隐藏一些底层细节。</p>
<h4 id="8-5-1-隐藏和导出过程名"><a href="#8-5-1-隐藏和导出过程名" class="headerlink" title="8.5.1 隐藏和导出过程名"></a>8.5.1 隐藏和导出过程名</h4><p>默认情况下，MASM使所有的过程都是public属性，即允许它们能被同一程序中任何其他模块调用。使用限定词PRIVATE可以覆盖这个属性</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysub proc private</span><br></pre></td></tr></table></figure>

<p>如果程序的启动模块使用了OPTIONPROC：PRIVATE，那么就应该将它（通常为main)指定为PUBLIC，<strong>否则操作系统加载器无法发现该启动模块</strong></p>
<h4 id="8-5-2-调用外部过程"><a href="#8-5-2-调用外部过程" class="headerlink" title="8.5.2 调用外部过程"></a>8.5.2 调用外部过程</h4><p>调用当前模块之外的过程时使用EXTERN伪指令，它确定过程名和堆栈帧大小。</p>
<p>过程名的后缀@n确定了已声明参数占用的堆栈空间总量（参见8.4节扩展PROC伪指令）。如果使用的是基本PROC伪指令，没有声明参数，那么EXTERN中的每个过程名后缀都为@0。若用扩展PROC伪指令声明一个过程，则每个参数占用4字节。</p>
<p>有时候可以用PROTO代替extern</p>
<h4 id="8-5-3-跨模块使用标量和符号"><a href="#8-5-3-跨模块使用标量和符号" class="headerlink" title="8.5.3 跨模块使用标量和符号"></a>8.5.3 跨模块使用标量和符号</h4><h5 id="1-导出变量和符号"><a href="#1-导出变量和符号" class="headerlink" title="1.导出变量和符号"></a>1.导出变量和符号</h5><h5 id="2-访问外部变量和符号"><a href="#2-访问外部变量和符号" class="headerlink" title="2.访问外部变量和符号"></a>2.访问外部变量和符号</h5><p><strong>对符号（由EQU和&#x3D;定义）而言，type应为ABS</strong>。对变量而言，type是数据定义属性，如BYTE、WORD、DWORD和SDWORD，可以包含PTR。</p>
<h5 id="3-使用带-EXTERNDEF的INCLUDE文件"><a href="#3-使用带-EXTERNDEF的INCLUDE文件" class="headerlink" title="3.使用带 EXTERNDEF的INCLUDE文件"></a>3.使用带 EXTERNDEF的INCLUDE文件</h5><p>MASM中一个很有用的伪指令EXTERNDEF可以代替PUBLIC和EXTERN。它可以放在文本文件中（类似C语言的.h文件），并用INCLUDE伪指令复制到每个程序模块。</p>
<p>电子PDF P279</p>
<h4 id="8-5-5-用Extern新建模块"><a href="#8-5-5-用Extern新建模块" class="headerlink" title="8.5.5 用Extern新建模块"></a>8.5.5 用Extern新建模块</h4><p>为了使源代码更加友好，用EQU伪指令再次定义了过程名</p>
<h4 id="8-5-6-用INVOKE和PROTO新建模块"><a href="#8-5-6-用INVOKE和PROTO新建模块" class="headerlink" title="8.5.6 用INVOKE和PROTO新建模块"></a>8.5.6 用INVOKE和PROTO新建模块</h4><p>与前面的PromptForlntegers版本比较，语句enter0，0和leave不见了，这是因为当MASM遇到PROC伪指令及其声明的参数时，会自动生成这两条语句。同样，RET指令也不需要自带常数参数了（PROC会处理好）</p>
<p>这些伪指令简化了很多细节，并为Windows API函数调用进行了优化</p>
<h4 id="8-5-7-课程回顾"><a href="#8-5-7-课程回顾" class="headerlink" title="8.5.7 课程回顾"></a>8.5.7 课程回顾</h4><p>链接OBJ模块比汇编ASM源文件快得多（对的）</p>
<h3 id="8-6-参数的高级用法（可选主题）"><a href="#8-6-参数的高级用法（可选主题）" class="headerlink" title="8.6 参数的高级用法（可选主题）"></a>8.6 参数的高级用法（可选主题）</h3><p>在查看由C和C++编译器创建的代码时，就有可能发现其中用到了将在下面说明的技术</p>
<h4 id="8-6-1-受USES运算符影响的堆栈"><a href="#8-6-1-受USES运算符影响的堆栈" class="headerlink" title="8.6.1 受USES运算符影响的堆栈"></a>8.6.1 受USES运算符影响的堆栈</h4><p>由于汇编器在过程开头插入了ECX和EDX的PUSH指令，使得堆栈参数的偏移量发生变化，<strong>从而导致结果错误</strong>，原本的EBP+8要改为EBP+16</p>
<p>使用PROC的高级语法就不会造成该问题</p>
<h4 id="8-6-2-向堆栈传递8位和16位参数"><a href="#8-6-2-向堆栈传递8位和16位参数" class="headerlink" title="8.6.2 向堆栈传递8位和16位参数"></a>8.6.2 向堆栈传递8位和16位参数</h4><p>16位操作数入栈，可能会使EBP不能对齐双字边界，从而可能导致出现页面失效、降低运行时性能。</p>
<p>PUSH指令不允许操作数为8位</p>
<h4 id="8-6-3-传递64位参数"><a href="#8-6-3-传递64位参数" class="headerlink" title="8.6.3 传递64位参数"></a>8.6.3 传递64位参数</h4><p>32位模式中，通过堆栈向子程序传递64位参数时，先将参数的<strong>高位双字入栈，再将其低位双字入栈</strong>。这样就使得整数在堆栈中是按照小端顺序（低字节在低地址）存放的，因而子程序容易检索到这些数值</p>
<h4 id="8-6-4-非双字局部变量"><a href="#8-6-4-非双字局部变量" class="headerlink" title="8.6.4 非双字局部变量"></a>8.6.4 非双字局部变量</h4><p>在声明不同大小的局部变量时，LOCAL伪指令的操作会变得很有趣。每个变量都按照其大小来分配空间：</p>
<p>8位的变量分配给下一个可用的字节，</p>
<p>16位的变量分配给下一个偶地址（字对齐），</p>
<p>32位变量分配给下一个双字对齐的地址。</p>
<p>由于32位模式中，<strong>堆栈偏移量默认为32位</strong></p>
<p>虽然SwapFlag只是一个字节变量，但是ESP还是会下移到堆栈中下一个双字的位置。</p>
<p>对嵌套调用来说，不论程序执行到哪一步，<strong>运行时堆栈</strong>（用.stack指令进行声明）都必须大到能够容纳下全部的活跃局部变量。</p>
<p>若过程为递归调用，则堆栈空间大约为其<strong>局部变量</strong>与<strong>参数总的大小</strong>乘以<strong>预计的递归次数</strong></p>
<h3 id="8-7-Java字节码（可选主题）"><a href="#8-7-Java字节码（可选主题）" class="headerlink" title="8.7 Java字节码（可选主题）"></a>8.7 Java字节码（可选主题）</h3><p>Java虚拟机的指令集与×86处理器系列的指令集有很大的不同。它采用面向堆栈的方法实现计算、比较和分支，与×86指令经常使用寄存器和内存操作数形成了鲜明的对比。</p>
<h3 id="8-8-本章小结"><a href="#8-8-本章小结" class="headerlink" title="8.8 本章小结"></a>8.8 本章小结</h3><p>过程参数有两种基本类型：寄存器参数和堆栈参数</p>
<p>堆栈帧（或活动记录）是为过程返回地址、传递参数、局部变量和被保存寄存器预留的堆栈区域。运行中的程序在开始执行过程的时候就会创建堆栈帧</p>
<p>LOCAL伪指令在过程内部声明一个或多个局部变量，它必须紧跟在PROC伪指令的后面。</p>
<h2 id="9-字符串和数组"><a href="#9-字符串和数组" class="headerlink" title="9 字符串和数组"></a>9 字符串和数组</h2><h3 id="9-2-字符串基本指令"><a href="#9-2-字符串基本指令" class="headerlink" title="9.2 字符串基本指令"></a>9.2 字符串基本指令</h3><p>X86指令集有五组指令用于处理字节、字和双字数组。虽然它们被称为字符串原语（string primitives)，但它们并不局限于字符数组。</p>
<p>字符串原语能高效执行，因为它们会自动重复并增加数组索引。</p>
<p>示例：复制字符串</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">c1d ；清除方向标志位 </span><br><span class="line">mov esi,OFFSET stringl;ESI指向源串 </span><br><span class="line">mov edi,OFFSET string2;EDI执行目的串 </span><br><span class="line">mov ecx,10；计数器赋值为10 </span><br><span class="line">rep movsb；传送10个字节</span><br></pre></td></tr></table></figure>

<p>方向标志位根据方向标志位的状态，字符串基本指令增加或减少ESI和EDI（参见表9-2）。可以用CLD和STD指令显式修改方向标志位</p>
<p>CLD；正向</p>
<p>SLD；反向</p>
<h4 id="9-2-1-MOVSB、MOVSW和MOVSD"><a href="#9-2-1-MOVSB、MOVSW和MOVSD" class="headerlink" title="9.2.1 MOVSB、MOVSW和MOVSD"></a>9.2.1 MOVSB、MOVSW和MOVSD</h4><p>MOVSB、MOVSW和MOVSD指令将数据从ESI指向的内存位置复制到EDI指向的内存位置。（根据方向标志位的值）这两个寄存器自动地增加或减少</p>
<p>Mov string byte</p>
<p>Mov string word</p>
<p>Mov string double word</p>
<p>数组复制完成后，ESI和EDI将分别指向两个数组范围之外的一个位置（双字就会超出4字节）</p>
<h4 id="9-2-2-CMPSB、CMPSW和CMPSD"><a href="#9-2-2-CMPSB、CMPSW和CMPSD" class="headerlink" title="9.2.2 CMPSB、CMPSW和CMPSD"></a>9.2.2 CMPSB、CMPSW和CMPSD</h4><p>CMPSB、CMPSW和CMPSD指令比较ESI指向的内存操作数与EDI指向的内存操作数</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">.data </span><br><span class="line">source DWORD 1234h </span><br><span class="line">target DWORD 5678h </span><br><span class="line">.code </span><br><span class="line">mov esi,OFFSET source</span><br><span class="line">mov edi,OFFSET target </span><br><span class="line">cmpsd；比较双字 </span><br><span class="line">ja L1；若source&gt;target则跳转</span><br></pre></td></tr></table></figure>

<p>REPE前缀重复比较操作，并自动增加ESI和EDI，直到ECX等于0，或者发现了一对不相等的双字。</p>
<h4 id="9-2-3-SCASB、SCASW和SCASD"><a href="#9-2-3-SCASB、SCASW和SCASD" class="headerlink" title="9.2.3 SCASB、SCASW和SCASD"></a>9.2.3 SCASB、SCASW和SCASD</h4><p>SCASB、SCASW和SCASD指令分别将<strong>AL&#x2F;AX&#x2F;EAX</strong>中的值与EDI寻址的一个字节&#x2F;字&#x2F;双字进行<strong>比较</strong>。</p>
<p>用于扫描是否有匹配字符，配合REPE（equal）或REPZ(zero),未发现的话使用jnz强制退出</p>
<h4 id="9-2-4-STOSB、STOSW和STOSD"><a href="#9-2-4-STOSB、STOSW和STOSD" class="headerlink" title="9.2.4 STOSB、STOSW和STOSD"></a>9.2.4 STOSB、STOSW和STOSD</h4><p>STOSB、STOSW和STOSD指令分别将AL&#x2F;AX&#x2F;EAX的内容<strong>存入</strong>由EDI中偏移量指向的内存位置。EDI根据方向标志位的状态递增或递减。与REP前缀组合使用时，这些指令实现用同一个值填充字符串或数组的全部元素</p>
<p>实际上是重复填充</p>
<h4 id="9-2-5LODSB、LODSW和LODSD"><a href="#9-2-5LODSB、LODSW和LODSD" class="headerlink" title="9.2.5LODSB、LODSW和LODSD"></a>9.2.5LODSB、LODSW和LODSD</h4><p>LODSB、LODSW和LODSD指令分别从ESI指向的内存地址<strong>加载一个字节或一个字</strong>到AL&#x2F;AX&#x2F;EAX，<strong>加载到累加器的新值会覆盖其原来的内容</strong></p>
<p>LODS相当于两条指令</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">mov al,[esi]</span><br><span class="line">inc esi</span><br></pre></td></tr></table></figure>



<h3 id="9-3-部分字符串过程"><a href="#9-3-部分字符串过程" class="headerlink" title="9.3 部分字符串过程"></a>9.3 部分字符串过程</h3><p>本节将演示用Irvine32链接库中的几个过程来处理空字节结束的字符串</p>
<p>到电子PDF P312结束</p>
<h3 id="9-4-二位数组"><a href="#9-4-二位数组" class="headerlink" title="9.4 二位数组"></a>9.4 二位数组</h3><h4 id="9-4-1-行列顺序"><a href="#9-4-1-行列顺序" class="headerlink" title="9.4.1 行列顺序"></a>9.4.1 行列顺序</h4><p>本章主要讲的是<strong>行主序</strong>实现</p>
<h4 id="9-4-2-基址-变址操作数"><a href="#9-4-2-基址-变址操作数" class="headerlink" title="9.4.2 基址-变址操作数"></a>9.4.2 基址-变址操作数</h4><p>其中的方括号是必须的</p>
<p><strong>二维数组</strong> </p>
<p>按行访问一个二维数组时，行偏移量放在基址寄存器中，列偏移量放在变址寄存器中。</p>
<p>只要不涉及堆栈，EBP就不会动，EBX是基址</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line">.386 </span><br><span class="line">.model flat,stdcall</span><br><span class="line">.stack 4096</span><br><span class="line">ExitProcess PROTO,dwExitcode:DWORD</span><br><span class="line"></span><br><span class="line">.data</span><br><span class="line">tableB  BYTE  10h,  20h,  30h,  40h,  50h</span><br><span class="line">        BYTE  60h,  70h,  80h,  90h,  0A0h</span><br><span class="line">        BYTE  0B0h, 0C0h, 0D0h, 0E0h, 0F0h</span><br><span class="line">RowSize = 5</span><br><span class="line">msg1	BYTE &quot;Enter row number: &quot;,0</span><br><span class="line">msg2 BYTE &quot;The sum is: &quot;,0</span><br><span class="line"></span><br><span class="line">.code</span><br><span class="line">main PROC</span><br><span class="line"></span><br><span class="line">; Demonstrate Base-Index mode:</span><br><span class="line"></span><br><span class="line">	mov	  edx,OFFSET msg1			; &quot;Enter row number:&quot;</span><br><span class="line">	;call  WriteString</span><br><span class="line">	mov eax,1					; EAX = row number</span><br><span class="line"></span><br><span class="line">	mov	  ebx,OFFSET tableB</span><br><span class="line">	mov	  ecx,RowSize</span><br><span class="line">	call  calc_row_sum				; EAX = sum</span><br><span class="line">   </span><br><span class="line">	mov	  edx,OFFSET msg2			; &quot;The sum is:&quot;</span><br><span class="line">	;call  WriteString</span><br><span class="line">	;call  WriteHex					; write sum in EAX</span><br><span class="line">	;call  Crlf</span><br><span class="line"></span><br><span class="line">main ENDP</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">;------------------------------------------------------------</span><br><span class="line">calc_row_sum PROC uses ebx ecx edx esi</span><br><span class="line">;</span><br><span class="line">; Calculates the sum of a row in a byte matrix.</span><br><span class="line">; Receives: EBX = table offset, EAX = row index, </span><br><span class="line">;		    ECX = row size, in bytes.</span><br><span class="line">; Returns:  EAX holds the sum.</span><br><span class="line">;------------------------------------------------------------</span><br><span class="line"></span><br><span class="line">	mul	 ecx			; row index * row size</span><br><span class="line">	add	 ebx,eax		; row offset</span><br><span class="line">	mov	 eax,0		; accumulator</span><br><span class="line">	mov	 esi,0		; column index</span><br><span class="line"></span><br><span class="line">L1:	movzx edx,BYTE PTR[ebx + esi]		; get a byte</span><br><span class="line">	add	 eax,edx						; add to accumulator</span><br><span class="line">	inc	 esi							; next byte in row</span><br><span class="line">	loop L1</span><br><span class="line"></span><br><span class="line">	ret</span><br><span class="line">calc_row_sum ENDP</span><br><span class="line"></span><br><span class="line">END main</span><br></pre></td></tr></table></figure>



<h5 id="2-比例因子"><a href="#2-比例因子" class="headerlink" title="2.比例因子"></a>2.比例因子</h5><p>如果是为<strong>字</strong>数组编写代码，则需要将变<strong>址操作数</strong>乘以<strong>比例因子</strong>2。</p>
<p>使用type即可</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mov eax,[ebx+esi*type tableD]</span><br></pre></td></tr></table></figure>



<h4 id="9-4-3-基址一变址一偏移量操作数"><a href="#9-4-3-基址一变址一偏移量操作数" class="headerlink" title="9.4.3 基址一变址一偏移量操作数"></a>9.4.3 基址一变址一偏移量操作数</h4><p>基址一变址一偏移量操作数用一个偏移量、一个基址寄存器、一个变址寄存器和一个可选的比例因子来生成有效地址。</p>
<p>base基址 index变址  displacement偏移量操作数</p>
<p>偏移量相当于移动基址</p>
<h4 id="9-4-4-64位模式下的基址一变址操作数"><a href="#9-4-4-64位模式下的基址一变址操作数" class="headerlink" title="9.4.4 64位模式下的基址一变址操作数"></a>9.4.4 64位模式下的基址一变址操作数</h4><h3 id="9-5-整数数组的检索和排序"><a href="#9-5-整数数组的检索和排序" class="headerlink" title="9.5 整数数组的检索和排序"></a>9.5 整数数组的检索和排序</h3><h4 id="9-5-1-冒泡排序"><a href="#9-5-1-冒泡排序" class="headerlink" title="9.5.1 冒泡排序"></a>9.5.1 冒泡排序</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">;----------------------------------------------------------</span><br><span class="line">BubbleSort PROC USES eax ecx esi,</span><br><span class="line">	pArray:PTR DWORD,		; pointer to array</span><br><span class="line">	Count:DWORD			; array size</span><br><span class="line">;</span><br><span class="line">; Sort an array of 32-bit signed integers in ascending order</span><br><span class="line">; using the bubble sort algorithm.</span><br><span class="line">; Receives: pointer to array, array size</span><br><span class="line">; Returns: nothing</span><br><span class="line">;-----------------------------------------------------------</span><br><span class="line"></span><br><span class="line">	mov ecx,Count</span><br><span class="line">	dec ecx			; decrement count by 1</span><br><span class="line"></span><br><span class="line">L1:	push ecx			; save outer loop count</span><br><span class="line">	mov	esi,pArray	; point to first value</span><br><span class="line"></span><br><span class="line">L2:	mov	eax,[esi]		; get array value</span><br><span class="line">	cmp	[esi+4],eax	; compare a pair of values</span><br><span class="line">	jge	L3			; if [esi] &lt;= [edi], don&#x27;t exch</span><br><span class="line">	xchg eax,[esi+4]	; exchange the pair</span><br><span class="line">	mov	[esi],eax</span><br><span class="line"></span><br><span class="line">L3:	add	esi,4		; move both pointers forward</span><br><span class="line">	loop	L2			; inner loop</span><br><span class="line"></span><br><span class="line">	pop	ecx			; retrieve outer loop count</span><br><span class="line">	loop L1			; else repeat outer loop</span><br><span class="line"></span><br><span class="line">L4:	ret</span><br><span class="line">BubbleSort ENDP</span><br></pre></td></tr></table></figure>



<h4 id="9-5-2-对半查找"><a href="#9-5-2-对半查找" class="headerlink" title="9.5.2 对半查找"></a>9.5.2 对半查找</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line">.code</span><br><span class="line">;-------------------------------------------------------------</span><br><span class="line">BinarySearch PROC USES ebx edx esi edi,</span><br><span class="line">	pArray:PTR DWORD,		; pointer to array</span><br><span class="line">	Count:DWORD,			; array size</span><br><span class="line">	searchVal:DWORD			; search value</span><br><span class="line">LOCAL first:DWORD,			; first position</span><br><span class="line">	last:DWORD,				; last position</span><br><span class="line">	mid:DWORD				; midpoint</span><br><span class="line">;</span><br><span class="line">; Search an array of signed integers for a single value.</span><br><span class="line">; Receives: Pointer to array, array size, search value.</span><br><span class="line">; Returns: If a match is found, EAX = the array position of the</span><br><span class="line">; matching element; otherwise, EAX = -1.</span><br><span class="line">;-------------------------------------------------------------</span><br><span class="line">	mov	 first,0			; first = 0</span><br><span class="line">	mov	 eax,Count			; last = (count - 1)</span><br><span class="line">	dec	 eax</span><br><span class="line">	mov	 last,eax</span><br><span class="line">	mov	 edi,searchVal		; EDI = searchVal</span><br><span class="line">	mov	 ebx,pArray			; EBX points to the array</span><br><span class="line"></span><br><span class="line">L1: ; while first &lt;= last</span><br><span class="line">	mov	 eax,first</span><br><span class="line">	cmp	 eax,last</span><br><span class="line">	jg	 L5					; exit search</span><br><span class="line"></span><br><span class="line">; mid = (last + first) / 2</span><br><span class="line">	mov	 eax,last</span><br><span class="line">	add	 eax,first</span><br><span class="line">	shr	 eax,1 ;用右移代替除法</span><br><span class="line">	mov	 mid,eax</span><br><span class="line"></span><br><span class="line">; EDX = values[mid]</span><br><span class="line">	mov	 esi,mid</span><br><span class="line">	shl	 esi,2				; scale mid value by 4</span><br><span class="line">	mov	 edx,[ebx+esi]		; EDX = values[mid]</span><br><span class="line"></span><br><span class="line">; if ( EDX &lt; searchval(EDI) )</span><br><span class="line">;	first = mid + 1;</span><br><span class="line">	cmp	 edx,edi</span><br><span class="line">	jge	 L2</span><br><span class="line">	mov	 eax,mid				; first = mid + 1</span><br><span class="line">	inc	 eax</span><br><span class="line">	mov	 first,eax</span><br><span class="line">	jmp	 L4</span><br><span class="line"></span><br><span class="line">; else if( EDX &gt; searchVal(EDI) )</span><br><span class="line">;	last = mid - 1;</span><br><span class="line">L2:	cmp	 edx,edi</span><br><span class="line">	jle	 L3</span><br><span class="line">	mov	 eax,mid				; last = mid - 1</span><br><span class="line">	dec	 eax</span><br><span class="line">	mov	 last,eax</span><br><span class="line">	jmp	 L4</span><br><span class="line"></span><br><span class="line">; else return mid</span><br><span class="line">L3:	mov	 eax,mid  				; value found</span><br><span class="line">	jmp	 L9						; return (mid)</span><br><span class="line"></span><br><span class="line">L4:	jmp	 L1						; continue the loop</span><br><span class="line"></span><br><span class="line">L5:	mov	 eax,-1					; search failed</span><br><span class="line">L9:	ret</span><br><span class="line">BinarySearch ENDP</span><br><span class="line">END</span><br></pre></td></tr></table></figure>



<h4 id="9-6-Java字节码：字符串处理（可选主题）"><a href="#9-6-Java字节码：字符串处理（可选主题）" class="headerlink" title="9.6 Java字节码：字符串处理（可选主题）"></a>9.6 Java字节码：字符串处理（可选主题）</h4><h4 id="9-7-本章小结"><a href="#9-7-本章小结" class="headerlink" title="9.7 本章小结"></a>9.7 本章小结</h4><p>数组操作是计算密集型的，因为一般它会涉及循环算法。大多数程序80%~90%的运行时间都用来执行其代码的一小部分。因此，通过减少循环中指令的条数和复杂度就可以提高软件的速度。<strong>由于汇编语言能控制每个细节，所以它是极好的代码优化工具</strong>。比如，通过用寄存器来代替内存变量，就能够优化代码块。或者可以使用本章介绍的字符串处理指令，而不是用MOV和CMP指令。</p>
<h2 id="10-结构和宏"><a href="#10-结构和宏" class="headerlink" title="10 结构和宏"></a>10 结构和宏</h2><h3 id="10-1-结构"><a href="#10-1-结构" class="headerlink" title="10.1 结构"></a>10.1 结构</h3><p>结构（structure)是一组逻辑相关变量的模板或模式。结构中的变量被称为字段（fields）。程序语句可以把结构作为整体进行访问，也可以访问其中的单个字段。结构常常包含不同类型的字段。联合（union)也会把多个标识符组织在一起，但是这些标识符会在内存同一区域内相互重叠。联合将在10.1.7节介绍。</p>
<p>（就是结构体和共用体）</p>
<p>COORD结构</p>
<p>WindowsAPI中定义的COORD结构确定了屏幕的X和Y坐标。相对于结构起始地址，<strong>字段X的偏移量为0，字段Y的偏移量为2</strong></p>
<h4 id="10-1-1-定义结构"><a href="#10-1-1-定义结构" class="headerlink" title="10.1.1 定义结构"></a>10.1.1 定义结构</h4><p>定义结构使用的是STRUCT和ENDS伪指令。在结构内，定义字段的语法与一般的变量定义是相同的。结构对其包含字段的数量几乎没有任何限制</p>
<h5 id="对齐结构字段"><a href="#对齐结构字段" class="headerlink" title="对齐结构字段"></a>对齐结构字段</h5><p>汇编语言中的ALIGN伪指令会使其后的字段或变量按地址对齐：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ALIGN datatype</span><br></pre></td></tr></table></figure>



<h4 id="10-1-2-声明结构变量"><a href="#10-1-2-声明结构变量" class="headerlink" title="10.1.2 声明结构变量"></a>10.1.2 声明结构变量</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.data </span><br><span class="line">point1 COORD&lt;5,10&gt;；X=5，Y=10 </span><br><span class="line">point2 COORD&lt;20&gt;；x=20，Y=?</span><br><span class="line">point3 COORD&lt;&gt;；X=?,Y=?</span><br><span class="line">worker Employee&lt;&gt;；默认初始值</span><br></pre></td></tr></table></figure>



<h4 id="10-1-3-引用结构变量"><a href="#10-1-3-引用结构变量" class="headerlink" title="10.1.3 引用结构变量"></a>10.1.3 引用结构变量</h4><p>使用TYPE和SIZEOF运算符可以引用结构变量和结构名称。</p>
<p>复习一下，type运算符返回的是标识符存储类型的字节数</p>
<h5 id="1-引用成员"><a href="#1-引用成员" class="headerlink" title="1.引用成员"></a>1.引用成员</h5><p>以下为对worker(一个Employee)的运行时引用：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">.data </span><br><span class="line">worker Employee&lt;&gt; </span><br><span class="line">.code </span><br><span class="line">mov dx,worker.Years </span><br><span class="line">mov worker.SalaryHistory,20000；第一个工资 </span><br><span class="line">mov [worker.SalaryHistory+4],30000；第二个工资 </span><br></pre></td></tr></table></figure>

<p>使用OFFSET运算符使用OFFSET运算符能获得结构变量中一个字段的地址：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mov edx,OFESET worker.LastName</span><br></pre></td></tr></table></figure>



<h5 id="2-间接和变址操作数"><a href="#2-间接和变址操作数" class="headerlink" title="2.间接和变址操作数"></a>2.间接和变址操作数</h5><p> 下面的语句不能汇编，原因是Years自身不能表明它所属的结构：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mov ax,[esi].Years；无效</span><br></pre></td></tr></table></figure>



<p>下述语句访问的是索引位置为1的雇员的Years字段：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.data </span><br><span class="line">department Employee 5 DUP(&lt;&gt;) </span><br><span class="line">.code </span><br><span class="line">mov esi,TYPE Employee；索引=1 </span><br><span class="line">mov department[esi].Years,4</span><br></pre></td></tr></table></figure>

<h5 id="-1"><a href="#-1" class="headerlink" title=""></a></h5><h5 id="3-对齐的结构成员的性能"><a href="#3-对齐的结构成员的性能" class="headerlink" title="3.对齐的结构成员的性能"></a>3.对齐的结构成员的性能</h5><p>对齐肯定比不对齐要快，但实际还要看CPU如何处理数据，有些情况下相差不大</p>
<h4 id="10-1-5-结构包含结构"><a href="#10-1-5-结构包含结构" class="headerlink" title="10.1.5 结构包含结构"></a>10.1.5 结构包含结构</h4><p>结构还可以包含其他结构的实例。例如，Rectangle可以用其左上角和右下角来定义，而它们都是COORD结构：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Rectangle STRUCT</span><br><span class="line">UpperLeft COORD&lt;&gt;</span><br><span class="line">LowerRight COORD&lt;&gt;</span><br><span class="line">Rectangle ENDS</span><br></pre></td></tr></table></figure>

<p>下面是对其一个结构字段的直接引用：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mov rect1.UpperLeft.x,10</span><br></pre></td></tr></table></figure>



<pre><code>OFFSET运算符能返回单个结构字段的指针，包括嵌套字段：
mov edi,OFFSET rect2.LowerRight 
moV (COORD PTR [edi]).x,50 
mov edi,OFFSET rect2.LowerRight.X 
mov WORDPTR [edi],50
好好想想，过程是正确的
</code></pre>
<h4 id="10-1-6-声明和使用联合"><a href="#10-1-6-声明和使用联合" class="headerlink" title="10.1.6 声明和使用联合"></a>10.1.6 声明和使用联合</h4><p>即：如何使用结构体</p>
<h3 id="10-2-宏"><a href="#10-2-宏" class="headerlink" title="10.2 宏"></a>10.2 宏</h3><h4 id="10-2-1-概述"><a href="#10-2-1-概述" class="headerlink" title="10.2.1 概述"></a>10.2.1 概述</h4><p>宏过程（macro procedure)是一个命名的汇编语句块。一旦定义好了，它就可以在程序中多次被调用。在调用宏过程时，其代码的副本将被直接插入到程序中该宏被调用的位置。</p>
<p>位置宏定义一般出现在程序源代码开始的位置，或者是放在独立文件中，再用INCLUDE伪指令复制到程序里。</p>
<p>宏在汇编器预处理（preprocessing)阶段进行扩展</p>
<h4 id="10-2-2-定义宏"><a href="#10-2-2-定义宏" class="headerlink" title="10.2.2 定义宏"></a>10.2.2 定义宏</h4><p>定义一个宏使用的是MACRO和ENDM伪指令</p>
<p>通过弹出和进入堆栈控制参数</p>
<h4 id="10-2-3-调用宏"><a href="#10-2-3-调用宏" class="headerlink" title="10.2.3 调用宏"></a>10.2.3 调用宏</h4><p>提示通常，与过程相比，宏执行起来更快，其原因是过程的CALL和RET指令需要额外的开销。但是，使用宏也有缺点：<strong>重复使用大型宏会增加程序的大小</strong>，因为，每次调用宏都会在程序中插入宏代码的一个新副本。</p>
<h5 id="调试宏"><a href="#调试宏" class="headerlink" title="调试宏"></a>调试宏</h5><p>调试使用了宏的程序相当具有挑战性。</p>
<p>电子PDF P344页</p>
<p>调试使用了宏的程序相当具有挑战性。程序汇编之后，检查其列表文件（扩展名为.LST）以确保每个宏都按照程序员的要求展开。</p>
<h4 id="10-2-4-其他宏特性"><a href="#10-2-4-其他宏特性" class="headerlink" title="10.2.4 其他宏特性"></a>10.2.4 其他宏特性</h4><h5 id="1-规定形参"><a href="#1-规定形参" class="headerlink" title="1.规定形参"></a>1.规定形参</h5><p><strong>利用REQ限定符，可以指定必需的宏形参</strong>。如果被调用的宏没有实参与规定形参相匹配，那么汇编器将显示出错消息。</p>
<h5 id="2-宏注释"><a href="#2-宏注释" class="headerlink" title="2.宏注释"></a>2.宏注释</h5><p>宏定义中的注释行一般都出现在每次宏展开的时候。如果希望忽略宏展开时的注释，就在它们的前面添加双分号（；；）。</p>
<h5 id="3-ECHO伪指令"><a href="#3-ECHO伪指令" class="headerlink" title="3.ECHO伪指令"></a>3.ECHO伪指令</h5><p>在程序汇编时，ECHO伪指令写一个字符串到标准输出。</p>
<p>Visual Studio2012的控制台窗口不会捕捉ECHO伪指令的输出，需要特殊配置完以后才行</p>
<h5 id="4-LOCAL伪指令"><a href="#4-LOCAL伪指令" class="headerlink" title="4.LOCAL伪指令"></a>4.LOCAL伪指令</h5><p>宏定义中常常包含了标号，并会在其代码中对这些标号进行自引用</p>
<p>使用local标记标号，预处理程序就会把标号名称转换为唯一标识符</p>
<p>汇编器生成的标号名使用了?？nnnn的形式</p>
<h5 id="5-包含代码和数据的宏"><a href="#5-包含代码和数据的宏" class="headerlink" title="5.包含代码和数据的宏"></a>5.包含代码和数据的宏</h5><p>宏通常既包含代码又包含数据，数据也会附上唯一标识符</p>
<h5 id="6-宏嵌套"><a href="#6-宏嵌套" class="headerlink" title="6.宏嵌套"></a>6.宏嵌套</h5><p>被嵌套的宏（nested macro)</p>
<h4 id="10-2-5使用本书的宏库（仅32位模式）"><a href="#10-2-5使用本书的宏库（仅32位模式）" class="headerlink" title="10.2.5使用本书的宏库（仅32位模式）"></a>10.2.5使用本书的宏库（仅32位模式）</h4><h4 id="10-2-7本节回顾"><a href="#10-2-7本节回顾" class="headerlink" title="10.2.7本节回顾"></a>10.2.7本节回顾</h4><p>1.（真&#x2F;假）：当一个宏被调用时，CALL和RET指令将自动插入到汇编程序中。</p>
<p>应该是真的，还需要细究</p>
<h3 id="10-3-条件汇编伪指令"><a href="#10-3-条件汇编伪指令" class="headerlink" title="10.3 条件汇编伪指令"></a>10.3 条件汇编伪指令</h3><h4 id="10-3-1-检查缺失的参数"><a href="#10-3-1-检查缺失的参数" class="headerlink" title="10.3.1 检查缺失的参数"></a>10.3.1 检查缺失的参数</h4><p>宏能够检查其参数是否为空。通常，宏若接收到空参数，则预处理程序在进行宏展开时会导致出现<strong>无效指令</strong></p>
<p>为了防止由于操作数缺失而导致的错误，可以使用IFB（if blank)伪指令，若宏实参为空，则该伪指令返回值为真。还可以使用IFNB（if not blank)运算符，若宏实参不为空，则返回值为真</p>
<p>EXITM伪指令告诉预处理程序退出宏，不再展开更多宏语句。</p>
<h4 id="10-3-2-默认参数初始值设定"><a href="#10-3-2-默认参数初始值设定" class="headerlink" title="10.3.2 默认参数初始值设定"></a>10.3.2 默认参数初始值设定</h4><p>宏可以有默认参数初始值。如果调用宏出现了宏参数缺失，那么就可以使用默认参数。</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mWriteln MACRO text:=&lt;&quot;&quot;&gt; </span><br><span class="line">	mWrite text </span><br><span class="line">	call Crlf</span><br><span class="line">ENDM</span><br></pre></td></tr></table></figure>

<p>双引号中间必须有参数，否则汇编器会产生错误</p>
<h4 id="10-3-3-布尔表达式"><a href="#10-3-3-布尔表达式" class="headerlink" title="10.3.3 布尔表达式"></a>10.3.3 布尔表达式</h4><p>支持部分布尔表达式</p>
<p>电子PDF P356页</p>
<h4 id="10-3-4-IF，ELSE和ENDIF"><a href="#10-3-4-IF，ELSE和ENDIF" class="headerlink" title="10.3.4 IF，ELSE和ENDIF"></a>10.3.4 IF，ELSE和ENDIF</h4><p>IF伪指令的后面必须跟一个常量布尔表达式。该表达式可以包含整数常量、符号常量或者常量宏实参，但<strong>不能包含寄存器或变量名</strong>。</p>
<h4 id="10-3-5-IFIDN和IFIDNI伪指令"><a href="#10-3-5-IFIDN和IFIDNI伪指令" class="headerlink" title="10.3.5 IFIDN和IFIDNI伪指令"></a>10.3.5 IFIDN和IFIDNI伪指令</h4><p>IFIDNI伪指令在两个符号（包括宏参数名）之间进行<strong>不区分大小写</strong>的比较，如果它们相等，则返回真。</p>
<p>IFIDN伪指令执行的是<strong>区分大小写</strong>的比较。</p>
<p>如下面的宏mReadBuf(电子PDF 357页)，其第二个参数不能用EDX</p>
<p>因为当buffer的偏移量被送入EDX时，原来的值就会被覆盖。</p>
<p>在如下修改过的宏代码中，如果这个条件不满足，就会显示一条警告消息</p>
<h4 id="10-3-6-示例：矩阵行求和"><a href="#10-3-6-示例：矩阵行求和" class="headerlink" title="10.3.6 示例：矩阵行求和"></a>10.3.6 示例：矩阵行求和</h4><p>由于没有宏于USES伪指令功能相当，因此插入push和pop指令</p>
<p>电子PDF P359页 </p>
<p>若MOVZX右操作数为双字，那么指令不会汇编。所以，当eltType为DWORD时，需要用IFIDNI运算符另外编写一条MOV指令</p>
<p>带有条件汇编的片段需要标记为local</p>
<h4 id="10-3-7-特殊运算符"><a href="#10-3-7-特殊运算符" class="headerlink" title="10.3.7 特殊运算符"></a>10.3.7 特殊运算符</h4><p>&amp;替换运算符 </p>
<p>&lt;&gt;文本文字运算符</p>
<p>！文字字符运算符</p>
<p>% 条件展开符</p>
<h5 id="1-替换运算符（-amp-）"><a href="#1-替换运算符（-amp-）" class="headerlink" title="1.替换运算符（&amp;）"></a>1.替换运算符（&amp;）</h5><p>替换运算符（&amp;）解析对宏参数名的有歧义的引用，添加了&amp;运算符，它就会强制预处理程序在字符串文本中插入实参（如ECX）</p>
<h5 id="2-展开运算符（-）"><a href="#2-展开运算符（-）" class="headerlink" title="2.展开运算符（%）"></a>2.展开运算符（%）</h5><p>展开运算符（%）展开文本宏并将<strong>常量表达式</strong>转换为<strong>文本形式</strong>。</p>
<p>如果用TEXTEQU编写包含（SIZEOF array)的文本宏，那么该宏就可以展开为之后的代码行，实现数字输出</p>
<p>有点迷惑，在电子PDF P361页</p>
<p>@LINE是一个预先定义的汇编运算符，其功能为返回当前源代码行的编号</p>
<h5 id="3-文字文本运算符（-lt-gt-）"><a href="#3-文字文本运算符（-lt-gt-）" class="headerlink" title="3.文字文本运算符（&lt;&gt;）"></a>3.文字文本运算符（&lt;&gt;）</h5><p>文字文本（literal-text)运算符（&gt;)把一个或多个字符和符号组合成一个文字文本</p>
<p>如果用文字文本运算符将字符串括起来，那么预处理程序就会把<strong>尖括号内所有的文本当作一个宏实参</strong></p>
<h5 id="4-文本字符运算符（！）"><a href="#4-文本字符运算符（！）" class="headerlink" title="4.文本字符运算符（！）"></a>4.文本字符运算符（！）</h5><p>强制预处理程序<strong>把预先定义的运算符</strong>当作普通的字符</p>
<h4 id="10-3-8-宏函数"><a href="#10-3-8-宏函数" class="headerlink" title="10.3.8 宏函数"></a>10.3.8 宏函数</h4><p>宏函数与宏过程有相似的地方，它也为汇编语言语句列表分配一个名称。不同的地方在于，<strong>宏函数通过EXITM伪指令总是返回一个常量</strong>（整数或字符串）。</p>
<p>看的不太懂，好像是可以通过这个方案选择inc文件，书上举的案例，是在16位和32位之间让机器自动做出选择</p>
<p>电子pDF P364页</p>
<h3 id="10-4-定义重复语句块"><a href="#10-4-定义重复语句块" class="headerlink" title="10.4 定义重复语句块"></a>10.4 定义重复语句块</h3><p>MASM有许多循环伪指令用于生成重复的语句块：WHILE、REPEAT、FOR和FORC。<br>    与LOOP指令不同，这些伪指令只在汇编时起作用，并使用常量值作为循环条件和计数器：<br>    ·WHILE伪指令根据一个布尔表达式来重复语句块。<br>    ·REPEAT伪指令根据计数器的值来重复语句块。<br>    ·FOR伪指令通过遍历符号列表来重复语句块。<br>    ·FORC伪指令通过遍历字符串来重复语句块。</p>
<p>基本上和C语言的循环是一致的</p>
<h4 id="10-4-5-示例：链表"><a href="#10-4-5-示例：链表" class="headerlink" title="10.4.5 示例：链表"></a>10.4.5 示例：链表</h4><p>那里面的LABEL标签怎么就变成了Macro？</p>
<h3 id="10-5-本章小结"><a href="#10-5-本章小结" class="headerlink" title="10.5 本章小结"></a>10.5 本章小结</h3><p>结构自身不占内存空间，但是结构变量会占用内存</p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="https://www.mocusez.site">MocusEZ</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://www.mocusez.site/posts/79b6.html">https://www.mocusez.site/posts/79b6.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc/4.0" rel="external nofollow noreferrer" target="_blank">CC BY-NC 4.0</a> 许可协议。转载请注明来自 <a href="https://www.mocusez.site" target="_blank">Mox的笔记库</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"></div><div class="post_share"><div class="social-share" data-image="https://cdn.fuhao321.com/uploads/2009/1-200Z20S45cM.jpg" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/posts/b88b.html"><img class="prev-cover" src="https://cdn.jsdelivr.net/gh/mocusez/Photo/20210215/fuchou.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">记一次手机端渗透实战</div></div></a></div><div class="next-post pull-right"><a href="/posts/6db3.html"><img class="next-cover" src="https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=4088345299,2353129269&amp;fm=26&amp;gp=0.jpg" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">ACM笔记</div></div></a></div></nav><hr/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="fas fa-comments fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div id="waline-wrap"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="/img/head.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">MocusEZ</div><div class="author-info__description">探索未曾设想的道路</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">61</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">0</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">8</div></a></div><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/mocusez" rel="external nofollow noreferrer" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="mailto:285918468@qq.com" rel="external nofollow noreferrer" target="_blank" title="Email"><i class="fas fa-envelope"></i></a><a class="social-icon" href="/atom.xml" target="_blank" title="RSS"><i class="fas fa-rss"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">迎接新的明天</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80%E7%AC%94%E8%AE%B0"><span class="toc-number">1.</span> <span class="toc-text">汇编语言笔记</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5"><span class="toc-number">1.1.</span> <span class="toc-text">1基本概念</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%A6%82%E5%BF%B5"><span class="toc-number">1.1.1.</span> <span class="toc-text">1.2 虚拟机概念</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-3-%E6%95%B0%E6%8D%AE%E8%A1%A8%E7%A4%BA"><span class="toc-number">1.1.2.</span> <span class="toc-text">1.3 数据表示</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-1-%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%95%B4%E6%95%B0"><span class="toc-number">1.1.2.1.</span> <span class="toc-text">1.3.1 二进制整数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-2-%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8A%A0%E6%B3%95"><span class="toc-number">1.1.2.2.</span> <span class="toc-text">1.3.2 二进制加法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-3-%E6%95%B4%E6%95%B0%E5%82%A8%E5%AD%98%E5%A4%A7%E5%B0%8F"><span class="toc-number">1.1.2.3.</span> <span class="toc-text">1.3.3 整数储存大小</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-4-%E5%8D%81%E5%85%AD%E8%BF%9B%E5%88%B6%E6%95%B4%E6%95%B0"><span class="toc-number">1.1.2.4.</span> <span class="toc-text">1.3.4 十六进制整数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-5-%E5%8D%81%E5%85%AD%E8%BF%9B%E5%88%B6%E5%8A%A0%E6%B3%95"><span class="toc-number">1.1.2.5.</span> <span class="toc-text">1.3.5 十六进制加法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-6-%E6%9C%89%E7%AC%A6%E5%8F%B7%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%95%B4%E6%95%B0"><span class="toc-number">1.1.2.6.</span> <span class="toc-text">1.3.6  有符号二进制整数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-7-%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%87%8F%E6%B3%95"><span class="toc-number">1.1.2.7.</span> <span class="toc-text">1.3.7 二进制减法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-3-8-%E5%AD%97%E7%AC%A6%E5%AD%98%E5%82%A8"><span class="toc-number">1.1.2.8.</span> <span class="toc-text">1.3.8 字符存储</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-4-%E5%B8%83%E5%B0%94%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-number">1.1.3.</span> <span class="toc-text">1.4 布尔表达式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-5-%E6%9C%AC%E7%AB%A0%E5%B0%8F%E7%BB%93"><span class="toc-number">1.1.4.</span> <span class="toc-text">1.5 本章小结</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-x86%E5%A4%84%E7%90%86%E5%99%A8%E6%9E%B6%E6%9E%84"><span class="toc-number">1.2.</span> <span class="toc-text">2 x86处理器架构</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#2-1-%E4%B8%80%E8%88%AC%E6%A6%82%E5%BF%B5"><span class="toc-number">1.2.1.</span> <span class="toc-text">2.1 一般概念</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-1-%E5%9F%BA%E6%9C%AC%E5%BE%AE%E6%9C%BA%E8%AE%BE%E8%AE%A1"><span class="toc-number">1.2.1.1.</span> <span class="toc-text">2.1.1 基本微机设计</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-2-%E6%8C%87%E4%BB%A4%E6%89%A7%E8%A1%8C%E5%91%A8%E6%9C%9F"><span class="toc-number">1.2.1.2.</span> <span class="toc-text">2.1.2 指令执行周期</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-3-%E8%AF%BB%E5%8F%96%E5%86%85%E5%AD%98"><span class="toc-number">1.2.1.3.</span> <span class="toc-text">2.1.3 读取内存</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-1-4-%E5%8A%A0%E8%BD%BD%E5%B9%B6%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F"><span class="toc-number">1.2.1.4.</span> <span class="toc-text">2.1.4 加载并执行程序</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-2-32%E4%BD%8Dx86"><span class="toc-number">1.2.2.</span> <span class="toc-text">2.2 32位x86</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-1-%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F"><span class="toc-number">1.2.2.1.</span> <span class="toc-text">2.2.1 操作系统</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-2-%E5%9F%BA%E6%9C%AC%E6%89%A7%E8%A1%8C%E7%8E%AF%E5%A2%83"><span class="toc-number">1.2.2.2.</span> <span class="toc-text">2.2.2 基本执行环境</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%9F%BA%E6%9C%AC%E7%A8%8B%E5%BA%8F%E6%89%A7%E8%A1%8C%E5%AF%84%E5%AD%98%E5%99%A8"><span class="toc-number">1.2.2.2.1.</span> <span class="toc-text">基本程序执行寄存器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%80%9A%E7%94%A8%E5%AF%84%E5%AD%98%E5%99%A8"><span class="toc-number">1.2.2.2.2.</span> <span class="toc-text">通用寄存器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%AE%B5%E5%AF%84%E5%AD%98%E5%99%A8"><span class="toc-number">1.2.2.2.3.</span> <span class="toc-text">段寄存器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%8C%87%E4%BB%A4%E6%8C%87%E9%92%88%E5%AF%84%E5%AD%98%E5%99%A8"><span class="toc-number">1.2.2.2.4.</span> <span class="toc-text">指令指针寄存器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%A0%87%E5%BF%97%EF%BC%88flags%EF%BC%89%E5%AF%84%E5%AD%98%E5%99%A8"><span class="toc-number">1.2.2.2.5.</span> <span class="toc-text">标志（flags）寄存器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#MMX%E5%AF%84%E5%AD%98%E5%99%A8"><span class="toc-number">1.2.2.2.6.</span> <span class="toc-text">MMX寄存器</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#XMM-%E5%AF%84%E5%AD%98%E5%99%A8"><span class="toc-number">1.2.2.2.7.</span> <span class="toc-text">XMM 寄存器</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2-2-3-x86%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86"><span class="toc-number">1.2.2.3.</span> <span class="toc-text">2.2.3 x86内存管理</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-3-64%E4%BD%8D%E7%9A%84x86-64%E4%BD%8D%E5%A4%84%E7%90%86%E5%99%A8"><span class="toc-number">1.2.3.</span> <span class="toc-text">2.3 64位的x86-64位处理器</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-4-%E5%85%B8%E5%9E%8BX86%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E4%BB%B6"><span class="toc-number">1.2.4.</span> <span class="toc-text">2.4 典型X86计算机组件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-5-%E5%9F%BA%E6%9C%AC%E8%BE%93%E5%85%A5%E8%BE%93%E5%87%BA%E7%B3%BB%E7%BB%9F"><span class="toc-number">1.2.5.</span> <span class="toc-text">2.5 基本输入输出系统</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#2-5-1-I-x2F-O%E8%AE%BF%E9%97%AE%E5%B1%82%E6%AC%A1"><span class="toc-number">1.2.5.0.1.</span> <span class="toc-text">2.5.1 I&#x2F;O访问层次</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80%E5%9F%BA%E7%A1%80"><span class="toc-number">1.3.</span> <span class="toc-text">3 汇编语言基础</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-1-%E5%9F%BA%E6%9C%AC%E8%AF%AD%E8%A8%80%E5%85%83%E7%B4%A0"><span class="toc-number">1.3.1.</span> <span class="toc-text">3.1 基本语言元素</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-1-%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%B1%87%E7%BC%96%E8%AF%AD%E8%A8%80%E7%A8%8B%E5%BA%8F"><span class="toc-number">1.3.1.1.</span> <span class="toc-text">3.1.1 第一个汇编语言程序</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-2-%E6%95%B4%E6%95%B0%E5%B8%B8%E9%87%8F"><span class="toc-number">1.3.1.2.</span> <span class="toc-text">3.1.2 整数常量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-3-%E6%95%B4%E6%95%B0%E5%B8%B8%E9%87%8F%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-number">1.3.1.3.</span> <span class="toc-text">3.1.3 整数常量表达式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-4-%E5%AE%9E%E6%95%B0%E5%B8%B8%E9%87%8F"><span class="toc-number">1.3.1.4.</span> <span class="toc-text">3.1.4 实数常量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-5-%E5%AD%97%E7%AC%A6%E5%B8%B8%E9%87%8F"><span class="toc-number">1.3.1.5.</span> <span class="toc-text">3.1.5 字符常量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-6-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E9%87%8F"><span class="toc-number">1.3.1.6.</span> <span class="toc-text">3.1.6 字符串常量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-7-%E4%BF%9D%E7%95%99%E5%AD%97"><span class="toc-number">1.3.1.7.</span> <span class="toc-text">3.1.7 保留字</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-8-%E6%A0%87%E8%AF%86%E7%AC%A6"><span class="toc-number">1.3.1.8.</span> <span class="toc-text">3.1.8 标识符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-9-%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.3.1.9.</span> <span class="toc-text">3.1.9 伪指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-1-10-%E6%8C%87%E4%BB%A4"><span class="toc-number">1.3.1.10.</span> <span class="toc-text">3.1.10 指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E6%A0%87%E5%8F%B7"><span class="toc-number">1.3.1.10.1.</span> <span class="toc-text">1.标号</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E6%8C%87%E4%BB%A4%E5%8A%A9%E8%AE%B0%E7%AC%A6"><span class="toc-number">1.3.1.10.2.</span> <span class="toc-text">2.指令助记符</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.3.1.10.3.</span> <span class="toc-text">3.操作数</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-%E6%B3%A8%E9%87%8A"><span class="toc-number">1.3.1.10.4.</span> <span class="toc-text">4.注释</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#5-NOP%E7%A9%BA%E6%93%8D%E4%BD%9C%E6%8C%87%E4%BB%A4"><span class="toc-number">1.3.1.10.5.</span> <span class="toc-text">5.NOP空操作指令</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-2-%E6%95%B4%E6%95%B0%E5%8A%A0%E5%87%8F%E6%B3%95"><span class="toc-number">1.3.2.</span> <span class="toc-text">3.2 整数加减法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-1-AddTwo%E7%A8%8B%E5%BA%8F"><span class="toc-number">1.3.2.1.</span> <span class="toc-text">3.2.1 AddTwo程序</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B1%87%E7%BC%96%E4%BC%AA%E6%8C%87%E4%BB%A4%E5%9B%9E%E9%A1%BE"><span class="toc-number">1.3.2.1.1.</span> <span class="toc-text">汇编伪指令回顾</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-2-%E8%BF%90%E8%A1%8C%E5%92%8C%E8%B0%83%E8%AF%95AddTwo"><span class="toc-number">1.3.2.2.</span> <span class="toc-text">3.2.2 运行和调试AddTwo</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-3-%E7%A8%8B%E5%BA%8F%E6%A8%A1%E6%9D%BF"><span class="toc-number">1.3.2.3.</span> <span class="toc-text">3.2.3 程序模板</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-%E6%B1%87%E7%BC%96%EF%BC%8C%E9%93%BE%E6%8E%A5%E5%92%8C%E8%BF%90%E8%A1%8C%E7%A8%8B%E5%BA%8F"><span class="toc-number">1.3.3.</span> <span class="toc-text">3.3 汇编，链接和运行程序</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-1-%E6%B1%87%E7%BC%96-%E9%93%BE%E6%8E%A5-%E6%89%A7%E8%A1%8C%E5%91%A8%E6%9C%9F"><span class="toc-number">1.3.3.1.</span> <span class="toc-text">3.3.1 汇编-链接-执行周期</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-2-%E5%88%97%E8%A1%A8%E6%96%87%E4%BB%B6"><span class="toc-number">1.3.3.2.</span> <span class="toc-text">3.3.2 列表文件</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE"><span class="toc-number">1.3.4.</span> <span class="toc-text">3.4 定义数据</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-1-%E5%86%85%E9%83%A8%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B"><span class="toc-number">1.3.4.1.</span> <span class="toc-text">3.4.1 内部数据类型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-2-%E6%95%B0%E6%8D%AE%E5%AE%9A%E4%B9%89%E8%AF%AD%E5%8F%A5"><span class="toc-number">1.3.4.2.</span> <span class="toc-text">3.4.2 数据定义语句</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-3-%E5%90%91AddTwo%E7%A8%8B%E5%BA%8F%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%8F%98%E9%87%8F"><span class="toc-number">1.3.4.3.</span> <span class="toc-text">3.4.3 向AddTwo程序添加一个变量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-4-%E5%AE%9A%E4%B9%89BYTE%E5%92%8CSBYTE%E6%95%B0%E6%8D%AE"><span class="toc-number">1.3.4.4.</span> <span class="toc-text">3.4.4 定义BYTE和SBYTE数据</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%A4%9A%E5%88%9D%E5%A7%8B%E5%80%BC"><span class="toc-number">1.3.4.4.1.</span> <span class="toc-text">1.多初始值</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%AE%9A%E4%B9%89%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-number">1.3.4.4.2.</span> <span class="toc-text">2.定义字符串</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-DUP%E6%93%8D%E4%BD%9C%E7%AC%A6"><span class="toc-number">1.3.4.4.3.</span> <span class="toc-text">3.DUP操作符</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-5-%E5%AE%9A%E4%B9%89word%E5%92%8Csword%E6%95%B0%E6%8D%AE"><span class="toc-number">1.3.4.5.</span> <span class="toc-text">3.4.5 定义word和sword数据</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-6-%E5%AE%9A%E4%B9%89dword%E5%92%8Cdsword"><span class="toc-number">1.3.4.6.</span> <span class="toc-text">3.4.6 定义dword和dsword</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-7-%E5%AE%9A%E4%B9%89qword%E6%95%B0%E6%8D%AE"><span class="toc-number">1.3.4.7.</span> <span class="toc-text">3.4.7 定义qword数据</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-8-%E5%AE%9A%E4%B9%89%E5%8E%8B%E7%BC%A9BCD%EF%BC%88TBYTE%EF%BC%89%E6%95%B0%E6%8D%AE"><span class="toc-number">1.3.4.8.</span> <span class="toc-text">3.4.8 定义压缩BCD（TBYTE）数据</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-9-%E5%AE%9A%E4%B9%89%E6%B5%AE%E7%82%B9%E7%B1%BB%E5%9E%8B"><span class="toc-number">1.3.4.9.</span> <span class="toc-text">3.4.9 定义浮点类型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-10-%E5%8F%98%E9%87%8F%E5%8A%A0%E6%B3%95%E7%A8%8B%E5%BA%8F"><span class="toc-number">1.3.4.10.</span> <span class="toc-text">3.4.10 变量加法程序</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-11-%E5%B0%8F%E7%AB%AF%E9%A1%BA%E5%BA%8F"><span class="toc-number">1.3.4.11.</span> <span class="toc-text">3.4.11 小端顺序</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-4-12-%E5%A3%B0%E6%98%8E%E6%9C%AA%E5%88%9D%E5%A7%8B%E5%8C%96%E6%95%B0%E6%8D%AE"><span class="toc-number">1.3.4.12.</span> <span class="toc-text">3.4.12 声明未初始化数据</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-%E7%AC%A6%E5%8F%B7%E5%B8%B8%E9%87%8F"><span class="toc-number">1.3.5.</span> <span class="toc-text">3.5 符号常量</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-1-%E7%AD%89%E5%8F%B7%E4%BC%AA%E6%8C%87%E4%BB%A4%EF%BC%88%E5%8C%85%E5%90%AB%E5%BD%93%E5%89%8D%E5%9C%B0%E5%9D%80%E8%AE%A1%E6%95%B0%E5%99%A8%EF%BC%89"><span class="toc-number">1.3.5.1.</span> <span class="toc-text">3.5.1 等号伪指令（包含当前地址计数器）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-2-%E8%AE%A1%E7%AE%97%E6%95%B0%E7%BB%84%E5%92%8C%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%A4%A7%E5%B0%8F"><span class="toc-number">1.3.5.2.</span> <span class="toc-text">3.5.2 计算数组和字符串的大小</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-3-EQU%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.3.5.3.</span> <span class="toc-text">3.5.3 EQU伪指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-5-4-TEXTQU%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.3.5.4.</span> <span class="toc-text">3.5.4 TEXTQU伪指令</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-6-64%E4%BD%8D%E7%BC%96%E7%A8%8B-%E7%A8%8B%E5%BA%8F%E6%A8%A1%E6%9D%BF"><span class="toc-number">1.3.6.</span> <span class="toc-text">3.6 64位编程(程序模板)</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-%E6%9C%AC%E7%AB%A0%E5%B0%8F%E7%BB%93"><span class="toc-number">1.3.7.</span> <span class="toc-text">3.7 本章小结</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-%E6%95%B0%E6%8D%AE%E4%BC%A0%E9%80%81%EF%BC%8C%E5%AF%BB%E5%9D%80%E5%92%8C%E7%AE%97%E6%95%B0%E8%BF%90%E7%AE%97"><span class="toc-number">1.4.</span> <span class="toc-text">4 数据传送，寻址和算数运算</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-%E6%95%B0%E6%8D%AE%E4%BC%A0%E9%80%81%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.1.</span> <span class="toc-text">4.1 数据传送指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-1%E5%BC%95%E8%A8%80"><span class="toc-number">1.4.1.1.</span> <span class="toc-text">4.1.1引言</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-2-%E6%93%8D%E4%BD%9C%E6%95%B0%E7%B1%BB%E5%9E%8B"><span class="toc-number">1.4.1.2.</span> <span class="toc-text">4.1.2 操作数类型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-3-%E7%9B%B4%E6%8E%A5%E5%86%85%E5%AD%98%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.4.1.3.</span> <span class="toc-text">4.1.3 直接内存操作数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-4-MOV%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.1.4.</span> <span class="toc-text">4.1.4 MOV指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%86%85%E5%AD%98%E5%88%B0%E5%86%85%E5%AD%98"><span class="toc-number">1.4.1.4.1.</span> <span class="toc-text">内存到内存</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%A6%86%E7%9B%96%E5%80%BC"><span class="toc-number">1.4.1.4.2.</span> <span class="toc-text">覆盖值</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-5-%E6%95%B4%E6%95%B0%E7%9A%84%E5%85%A8%E9%9B%B6-x2F-%E7%AC%A6%E5%8F%B7%E6%89%A9%E5%B1%95"><span class="toc-number">1.4.1.5.</span> <span class="toc-text">4.1.5 整数的全零&#x2F;符号扩展</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E6%8A%8A%E4%B8%80%E4%B8%AA%E8%BE%83%E5%B0%8F%E7%9A%84%E5%80%BC%E5%A4%8D%E5%88%B6%E5%88%B0%E4%B8%80%E4%B8%AA%E8%BE%83%E5%A4%A7%E7%9A%84%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.4.1.5.1.</span> <span class="toc-text">1.把一个较小的值复制到一个较大的操作数</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-MOVZX-%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.1.5.2.</span> <span class="toc-text">2.MOVZX 指令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-MOVSX-%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.1.5.3.</span> <span class="toc-text">3.MOVSX 指令</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-6-LAHF%E5%92%8CSAHF%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.1.6.</span> <span class="toc-text">4.1.6 LAHF和SAHF指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-7-XCHG%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.1.7.</span> <span class="toc-text">4.1.7 XCHG指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-8-%E7%9B%B4%E6%8E%A5-%E5%81%8F%E7%A7%BB%E9%87%8F%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.4.1.8.</span> <span class="toc-text">4.1.8 直接-偏移量操作数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-9-%E7%A4%BA%E4%BE%8B%E7%A8%8B%E5%BA%8F%EF%BC%88Moves%EF%BC%89"><span class="toc-number">1.4.1.9.</span> <span class="toc-text">4.1.9 示例程序（Moves）</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-%E5%8A%A0%E6%B3%95%E5%92%8C%E5%87%8F%E6%B3%95"><span class="toc-number">1.4.2.</span> <span class="toc-text">4.2 加法和减法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-1-INC%E5%92%8CDEC"><span class="toc-number">1.4.2.1.</span> <span class="toc-text">4.2.1 INC和DEC</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-2-add%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.2.2.</span> <span class="toc-text">4.2.2 add指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-3-sub%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.2.3.</span> <span class="toc-text">4.2.3 sub指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-4-NEG%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.2.4.</span> <span class="toc-text">4.2.4 NEG指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-5-%E6%89%A7%E8%A1%8C%E7%AE%97%E6%9C%AF%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-number">1.4.2.5.</span> <span class="toc-text">4.2.5 执行算术表达式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-6-%E5%8A%A0%E5%87%8F%E6%B3%95%E5%BD%B1%E5%93%8D%E7%9A%84%E6%A0%87%E5%BF%97%E4%BD%8D%EF%BC%88%EF%BC%81%EF%BC%89"><span class="toc-number">1.4.2.6.</span> <span class="toc-text">4.2.6 加减法影响的标志位（！）</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E6%97%A0%E7%AC%A6%E5%8F%B7%E6%95%B0%E8%BF%90%E7%AE%97-%E9%9B%B6%E6%A0%87%E5%BF%97%E4%BD%8D%E3%80%81%E8%BF%9B%E4%BD%8D%E6%A0%87%E5%BF%97%E4%BD%8D%E5%92%8C%E8%BE%85%E5%8A%A9%E8%BF%9B%E4%BD%8D%E6%A0%87%E5%BF%97%E4%BD%8D"><span class="toc-number">1.4.2.6.1.</span> <span class="toc-text">1.无符号数运算:零标志位、进位标志位和辅助进位标志位</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E6%9C%89%E7%AC%A6%E5%8F%B7%E8%BF%90%E7%AE%97%EF%BC%9A%E7%AC%A6%E5%8F%B7%E6%A0%87%E5%BF%97%E4%BD%8D%E5%92%8C%E6%BA%A2%E5%87%BA%E6%A0%87%E5%BF%97%E4%BD%8D"><span class="toc-number">1.4.2.6.2.</span> <span class="toc-text">2.有符号运算：符号标志位和溢出标志位</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-7-%E7%A4%BA%E4%BE%8B%E7%A8%8B%E5%BA%8F%EF%BC%88AddSubTest%EF%BC%89"><span class="toc-number">1.4.2.7.</span> <span class="toc-text">4.2.7 示例程序（AddSubTest）</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-3-%E4%B8%8E%E6%95%B0%E6%8D%AE%E7%9B%B8%E5%85%B3%E7%9A%84%E8%BF%90%E7%AE%97%E7%AC%A6%E5%92%8C%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.3.</span> <span class="toc-text">4.3 与数据相关的运算符和伪指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-1-OFFSET%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-number">1.4.3.1.</span> <span class="toc-text">4.3.1 OFFSET运算符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-2-ALIGN%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-number">1.4.3.2.</span> <span class="toc-text">4.3.2 ALIGN运算符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-3-PTR%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-number">1.4.3.3.</span> <span class="toc-text">4.3.3 PTR运算符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-4-TYPE%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-number">1.4.3.4.</span> <span class="toc-text">4.3.4 TYPE运算符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-5-LENGTHOF%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-number">1.4.3.5.</span> <span class="toc-text">4.3.5 LENGTHOF运算符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-6-SIZEOF%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-number">1.4.3.6.</span> <span class="toc-text">4.3.6 SIZEOF运算符</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-7-LABEL%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.3.7.</span> <span class="toc-text">4.3.7 LABEL伪指令</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-4-%E9%97%B4%E6%8E%A5%E5%AF%BB%E5%9D%80"><span class="toc-number">1.4.4.</span> <span class="toc-text">4.4 间接寻址</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-4-1-%E9%97%B4%E6%8E%A5%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.4.4.1.</span> <span class="toc-text">4.4.1 间接操作数</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#PTR%E4%B8%8E%E9%97%B4%E6%8E%A5%E6%93%8D%E4%BD%9C%E6%95%B0%E4%B8%80%E8%B5%B7%E4%BD%BF%E7%94%A8"><span class="toc-number">1.4.4.1.1.</span> <span class="toc-text">PTR与间接操作数一起使用</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-4-2-%E6%95%B0%E7%BB%84"><span class="toc-number">1.4.4.2.</span> <span class="toc-text">4.4.2 数组</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-4-3-%E5%8F%98%E5%9D%80%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.4.4.3.</span> <span class="toc-text">4.4.3 变址操作数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-4-4-%E6%8C%87%E9%92%88"><span class="toc-number">1.4.4.4.</span> <span class="toc-text">4.4.4 指针</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-4-5-%E6%9C%AC%E8%8A%82%E5%9B%9E%E9%A1%BE"><span class="toc-number">1.4.4.5.</span> <span class="toc-text">4.4.5 本节回顾</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-5-JMP%E5%92%8CLOOP%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.5.</span> <span class="toc-text">4.5 JMP和LOOP指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-5-1-JMP%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.5.1.</span> <span class="toc-text">4.5.1 JMP指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-5-2-LOOP%E6%8C%87%E4%BB%A4"><span class="toc-number">1.4.5.2.</span> <span class="toc-text">4.5.2 LOOP指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-5-3-%E5%9C%A8Visual-Studio%E8%B0%83%E8%AF%95%E5%99%A8%E4%B8%AD%E6%98%BE%E7%A4%BA%E6%95%B0%E7%BB%84"><span class="toc-number">1.4.5.3.</span> <span class="toc-text">4.5.3 在Visual Studio调试器中显示数组</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-5-4-%E6%95%B4%E6%95%B0%E6%95%B0%E7%BB%84%E6%B1%82%E5%92%8C"><span class="toc-number">1.4.5.4.</span> <span class="toc-text">4.5.4 整数数组求和</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-5-5-%E5%A4%8D%E5%88%B6%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-number">1.4.5.5.</span> <span class="toc-text">4.5.5 复制字符串</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-6-64%E4%BD%8D%E7%BC%96%E7%A8%8B"><span class="toc-number">1.4.6.</span> <span class="toc-text">4.6 64位编程</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-%E8%BF%87%E7%A8%8B"><span class="toc-number">1.5.</span> <span class="toc-text">5 过程</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-%E5%A0%86%E6%A0%88%E6%93%8D%E4%BD%9C"><span class="toc-number">1.5.1.</span> <span class="toc-text">5.1 堆栈操作</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-1-%E8%BF%90%E8%A1%8C%E6%97%B6%E5%A0%86%E6%A0%88%EF%BC%8832%E4%BD%8D%E6%A8%A1%E5%BC%8F%EF%BC%89"><span class="toc-number">1.5.1.1.</span> <span class="toc-text">5.1.1 运行时堆栈（32位模式）</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%85%A5%E6%A0%88%E6%93%8D%E4%BD%9C"><span class="toc-number">1.5.1.1.1.</span> <span class="toc-text">1.入栈操作</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%87%BA%E6%A0%88%E6%93%8D%E4%BD%9C"><span class="toc-number">1.5.1.1.2.</span> <span class="toc-text">2.出栈操作</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E5%A0%86%E6%A0%88%E5%BA%94%E7%94%A8"><span class="toc-number">1.5.1.1.3.</span> <span class="toc-text">3.堆栈应用</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-2-PUSH%E5%92%8CPOP%E6%8C%87%E4%BB%A4"><span class="toc-number">1.5.1.2.</span> <span class="toc-text">5.1.2 PUSH和POP指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-PUSH%E6%8C%87%E4%BB%A4"><span class="toc-number">1.5.1.2.1.</span> <span class="toc-text">1.PUSH指令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-POP%E6%8C%87%E4%BB%A4"><span class="toc-number">1.5.1.2.2.</span> <span class="toc-text">2.POP指令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-PUSHFD%E5%92%8CPOPFD%E6%8C%87%E4%BB%A4"><span class="toc-number">1.5.1.2.3.</span> <span class="toc-text">3.PUSHFD和POPFD指令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-PUSHAD-PUSHA-POPAD-POPA"><span class="toc-number">1.5.1.2.4.</span> <span class="toc-text">4.PUSHAD,PUSHA,POPAD,POPA</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%A4%BA%E4%BE%8B%EF%BC%9A%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8F%8D%E8%BD%AC"><span class="toc-number">1.5.1.2.5.</span> <span class="toc-text">示例：字符串反转</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-2-%E5%AE%9A%E4%B9%89%E5%B9%B6%E4%BD%BF%E7%94%A8%E8%BF%87%E7%A8%8B"><span class="toc-number">1.5.2.</span> <span class="toc-text">5.2 定义并使用过程</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-1-PROC%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.5.2.1.</span> <span class="toc-text">5.2.1 PROC伪指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%AE%9A%E4%B9%89%E8%BF%87%E7%A8%8B"><span class="toc-number">1.5.2.1.1.</span> <span class="toc-text">1.定义过程</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E8%BF%87%E7%A8%8B%E4%B8%AD%E7%9A%84%E6%A0%87%E5%8F%B7"><span class="toc-number">1.5.2.1.2.</span> <span class="toc-text">2.过程中的标号</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-2-CALL%E5%92%8CRET%E6%8C%87%E4%BB%A4"><span class="toc-number">1.5.2.2.</span> <span class="toc-text">5.2.2 CALL和RET指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%B0%83%E7%94%A8%E5%92%8C%E8%BF%94%E5%9B%9E%E7%A4%BA%E4%BE%8B"><span class="toc-number">1.5.2.2.1.</span> <span class="toc-text">调用和返回示例</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-3-%E8%BF%87%E7%A8%8B%E8%B0%83%E7%94%A8%E5%B5%8C%E5%A5%97"><span class="toc-number">1.5.2.3.</span> <span class="toc-text">5.2.3 过程调用嵌套</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-4-%E5%90%91%E8%BF%87%E7%A8%8B%E4%BC%A0%E9%80%92%E5%AF%84%E5%AD%98%E5%99%A8%E5%8F%82%E6%95%B0"><span class="toc-number">1.5.2.4.</span> <span class="toc-text">5.2.4 向过程传递寄存器参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-5-%E7%A4%BA%E4%BE%8B%EF%BC%9A%E6%95%B4%E6%95%B0%E6%95%B0%E7%BB%84%E6%B1%82%E5%92%8C"><span class="toc-number">1.5.2.5.</span> <span class="toc-text">5.2.5 示例：整数数组求和</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-2-6-%E4%BF%9D%E5%AD%98%E5%92%8C%E6%81%A2%E5%A4%8D%E5%AF%84%E5%AD%98%E5%99%A8"><span class="toc-number">1.5.2.6.</span> <span class="toc-text">5.2.6 保存和恢复寄存器</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BE%8B%E5%A4%96%E6%83%85%E5%86%B5%EF%BC%81%EF%BC%81%EF%BC%81"><span class="toc-number">1.5.2.6.1.</span> <span class="toc-text">例外情况！！！</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-3-%E9%93%BE%E6%8E%A5%E5%88%B0%E5%A4%96%E9%83%A8%E5%BA%93"><span class="toc-number">1.5.3.</span> <span class="toc-text">5.3 链接到外部库</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-3-1-%E8%83%8C%E6%99%AF%E7%9F%A5%E8%AF%86"><span class="toc-number">1.5.3.1.</span> <span class="toc-text">5.3.1 背景知识</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%93%BE%E6%8E%A5%E5%91%BD%E4%BB%A4%E9%80%89%E9%A1%B9"><span class="toc-number">1.5.3.1.1.</span> <span class="toc-text">链接命令选项</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-4-Irvine32-%E9%93%BE%E6%8E%A5%E5%BA%93"><span class="toc-number">1.5.4.</span> <span class="toc-text">5.4 Irvine32 链接库</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-4-1-%E5%88%9B%E5%BB%BA%E5%BA%93%E7%9A%84%E5%8A%A8%E6%9C%BA"><span class="toc-number">1.5.4.1.</span> <span class="toc-text">5.4.1 创建库的动机</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-4-2-%E6%A6%82%E8%BF%B0%E6%8E%A7%E5%88%B6%E5%8F%B0%E7%AA%97%E5%8F%A3"><span class="toc-number">1.5.4.2.</span> <span class="toc-text">5.4.2 概述控制台窗口</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-4-3-%E8%BF%87%E7%A8%8B%E8%AF%A6%E7%BB%86%E8%AF%B4%E6%98%8E"><span class="toc-number">1.5.4.3.</span> <span class="toc-text">5.4.3 过程详细说明</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#CloseFile"><span class="toc-number">1.5.4.3.1.</span> <span class="toc-text">CloseFile</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-4-4-%E5%BA%93%E6%B5%8B%E8%AF%95%E7%A8%8B%E5%BA%8F"><span class="toc-number">1.5.4.4.</span> <span class="toc-text">5.4.4 库测试程序</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B5%8B%E8%AF%951"><span class="toc-number">1.5.4.4.1.</span> <span class="toc-text">测试1</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B5%8B%E8%AF%953"><span class="toc-number">1.5.4.4.2.</span> <span class="toc-text">测试3</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-5-64%E4%BD%8D%E6%B1%87%E7%BC%96%E7%BC%96%E7%A8%8B"><span class="toc-number">1.5.5.</span> <span class="toc-text">5.5 64位汇编编程</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-%E6%9D%A1%E4%BB%B6%E5%A4%84%E7%90%86"><span class="toc-number">1.6.</span> <span class="toc-text">6 条件处理</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#6-1-%E6%9D%A1%E4%BB%B6%E5%88%86%E6%94%AF"><span class="toc-number">1.6.1.</span> <span class="toc-text">6.1 条件分支</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-2-%E5%B8%83%E5%B0%94%E5%92%8C%E6%AF%94%E8%BE%83%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.2.</span> <span class="toc-text">6.2 布尔和比较指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-1-CPU%E7%8A%B6%E6%80%81%E6%A0%87%E5%BF%97"><span class="toc-number">1.6.2.1.</span> <span class="toc-text">6.2.1 CPU状态标志</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-2-AND%E6%8C%87%E4%BB%A4%E7%AC%A6"><span class="toc-number">1.6.2.2.</span> <span class="toc-text">6.2.2 AND指令符</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%B0%86%E5%AD%97%E7%AC%A6%E8%BD%AC%E6%8D%A2%E4%B8%BA%E5%A4%A7%E5%86%99"><span class="toc-number">1.6.2.2.1.</span> <span class="toc-text">将字符转换为大写</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-3-OR%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.2.3.</span> <span class="toc-text">6.2.3 OR指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-4-%E4%BD%8D%E6%98%A0%E5%B0%84%E9%9B%86"><span class="toc-number">1.6.2.4.</span> <span class="toc-text">6.2.4 位映射集</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%A1%A5%E9%9B%86"><span class="toc-number">1.6.2.4.1.</span> <span class="toc-text">补集</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%BA%A4%E9%9B%86"><span class="toc-number">1.6.2.4.2.</span> <span class="toc-text">交集</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%B9%B6%E9%9B%86"><span class="toc-number">1.6.2.4.3.</span> <span class="toc-text">并集</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-5-XOR%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.2.5.</span> <span class="toc-text">6.2.5 XOR指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%A3%80%E6%9F%A5%E5%A5%87%E5%81%B6%E6%A0%87%E5%BF%97%E4%BD%8D"><span class="toc-number">1.6.2.5.1.</span> <span class="toc-text">检查奇偶标志位</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#16%E4%B8%BA%E5%A5%87%E5%81%B6%E6%80%A7%E4%BB%A5%E6%AD%A4%E7%B1%BB%E6%8E%A8"><span class="toc-number">1.6.2.5.2.</span> <span class="toc-text">16为奇偶性以此类推</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-6-NOT-%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.2.6.</span> <span class="toc-text">6.2.6 NOT 指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-7-TEST%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.2.7.</span> <span class="toc-text">6.2.7 TEST指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%A4%9A%E4%BD%8D%E6%B5%8B%E8%AF%95"><span class="toc-number">1.6.2.7.1.</span> <span class="toc-text">多位测试</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-8-CMP%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.2.8.</span> <span class="toc-text">6.2.8 CMP指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-9-%E7%BD%AE%E4%BD%8D%E5%92%8C%E6%B8%85%E9%99%A4%E5%8D%95%E4%B8%AACPU%E6%A0%87%E5%BF%97%E4%BD%8D"><span class="toc-number">1.6.2.9.</span> <span class="toc-text">6.2.9 置位和清除单个CPU标志位</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-2-10-64%E4%BD%8D%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E5%B8%83%E5%B0%94%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.2.10.</span> <span class="toc-text">6.2.10 64位模式下的布尔指令</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-3-%E6%9D%A1%E4%BB%B6%E8%B7%B3%E8%BD%AC"><span class="toc-number">1.6.3.</span> <span class="toc-text">6.3 条件跳转</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#6-3-1-%E6%9D%A1%E4%BB%B6%E7%BB%93%E6%9E%84"><span class="toc-number">1.6.3.1.</span> <span class="toc-text">6.3.1 条件结构</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-3-2-Jcond%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.3.2.</span> <span class="toc-text">6.3.2 Jcond指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-3-3-%E6%9D%A1%E4%BB%B6%E8%B7%B3%E8%BD%AC%E6%8C%87%E4%BB%A4%E7%B1%BB%E5%9E%8B"><span class="toc-number">1.6.3.3.</span> <span class="toc-text">6.3.3 条件跳转指令类型</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-3-4-%E6%9D%A1%E4%BB%B6%E8%B7%B3%E8%BD%AC%E5%BA%94%E7%94%A8"><span class="toc-number">1.6.3.4.</span> <span class="toc-text">6.3.4 条件跳转应用</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%B5%8B%E8%AF%95%E7%8A%B6%E6%80%81%E4%BD%8D"><span class="toc-number">1.6.3.4.1.</span> <span class="toc-text">测试状态位</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%B8%A4%E4%B8%AA%E6%95%B0%E4%B8%AD%E7%9A%84%E8%BE%83%E5%A4%A7%E6%95%B0"><span class="toc-number">1.6.3.4.2.</span> <span class="toc-text">两个数中的较大数</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E4%B8%89%E4%B8%AA%E6%95%B0%E7%9A%84%E6%9C%80%E5%B0%8F%E6%95%B0"><span class="toc-number">1.6.3.4.3.</span> <span class="toc-text">三个数的最小数</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-4-%E6%9D%A1%E4%BB%B6%E5%BE%AA%E7%8E%AF%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.4.</span> <span class="toc-text">6.4 条件循环指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#6-4-1-LOOPZ%E5%92%8CLOOPE%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.4.0.1.</span> <span class="toc-text">6.4.1 LOOPZ和LOOPE指令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#6-4-2-LOOPNZ%E5%92%8CLOOPNE%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.4.0.2.</span> <span class="toc-text">6.4.2 LOOPNZ和LOOPNE指令</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-5-%E6%9D%A1%E4%BB%B6%E7%BB%93%E6%9E%84"><span class="toc-number">1.6.5.</span> <span class="toc-text">6.5 条件结构</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#6-5-1-%E5%9D%97%E7%BB%93%E6%9E%84%E7%9A%84IF%E8%AF%AD%E5%8F%A5"><span class="toc-number">1.6.5.1.</span> <span class="toc-text">6.5.1 块结构的IF语句</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E7%99%BD%E7%9B%92%E6%B5%8B%E8%AF%95"><span class="toc-number">1.6.5.1.1.</span> <span class="toc-text">白盒测试</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-5-2-%E5%A4%8D%E5%90%88%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-number">1.6.5.2.</span> <span class="toc-text">6.5.2 复合表达式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-5-3-while%E5%BE%AA%E7%8E%AF"><span class="toc-number">1.6.5.3.</span> <span class="toc-text">6.5.3  while循环</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-5-4-%E8%A1%A8%E9%A9%B1%E5%8A%A8%E9%80%89%E6%8B%A9"><span class="toc-number">1.6.5.4.</span> <span class="toc-text">6.5.4 表驱动选择</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-6-%E5%BA%94%E7%94%A8%EF%BC%9A%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA%EF%BC%88FSM%EF%BC%89"><span class="toc-number">1.6.6.</span> <span class="toc-text">6.6 应用：有限状态机（FSM）</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#6-6-1-%E9%AA%8C%E8%AF%81%E8%BE%93%E5%85%A5%E5%AD%97%E7%AC%A6%E4%B8%B2"><span class="toc-number">1.6.6.0.1.</span> <span class="toc-text">6.6.1 验证输入字符串</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#6-6-2%E9%AA%8C%E8%AF%81%E6%9C%89%E7%AC%A6%E5%8F%B7%E6%95%B4%E6%95%B0"><span class="toc-number">1.6.6.0.2.</span> <span class="toc-text">6.6.2验证有符号整数</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-7-%E6%9D%A1%E4%BB%B6%E6%8E%A7%E5%88%B6%E6%B5%81%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.6.7.</span> <span class="toc-text">6.7 条件控制流伪指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#6-7-1-%E6%96%B0%E5%BB%BAIF%E8%AF%AD%E5%8F%A5"><span class="toc-number">1.6.7.1.</span> <span class="toc-text">6.7.1 新建IF语句</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-7-2-%E6%9C%89%E7%AC%A6%E5%8F%B7%E6%95%B0%E5%92%8C%E6%97%A0%E7%AC%A6%E5%8F%B7%E6%95%B0%E7%9A%84%E6%AF%94%E8%BE%83"><span class="toc-number">1.6.7.2.</span> <span class="toc-text">6.7.2 有符号数和无符号数的比较</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link"><span class="toc-number">1.6.7.2.1.</span> <span class="toc-text"></span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%9C%89%E7%AC%A6%E5%8F%B7%E6%AF%94%E8%BE%83"><span class="toc-number">1.6.7.2.2.</span> <span class="toc-text">有符号比较</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%AF%84%E5%AD%98%E5%99%A8%E6%AF%94%E8%BE%83"><span class="toc-number">1.6.7.2.3.</span> <span class="toc-text">寄存器比较</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-7-3-%E5%A4%8D%E5%90%88%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-number">1.6.7.3.</span> <span class="toc-text">6.7.3 复合表达式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-7-4-%E7%94%A8-REPEAT%E5%92%8C-WHILE%E5%88%9B%E5%BB%BA%E5%BE%AA%E7%8E%AF"><span class="toc-number">1.6.7.4.</span> <span class="toc-text">6.7.4 用.REPEAT和.WHILE创建循环</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#6-8-%E6%9C%AC%E7%AB%A0%E5%B0%8F%E7%BB%93"><span class="toc-number">1.6.7.5.</span> <span class="toc-text">6.8 本章小结</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-%E6%95%B4%E6%95%B0%E8%BF%90%E7%AE%97"><span class="toc-number">1.7.</span> <span class="toc-text">7 整数运算</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#7-1-%E7%A7%BB%E4%BD%8D%E5%92%8C%E5%BE%AA%E7%8E%AF%E7%A7%BB%E4%BD%8D%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.1.</span> <span class="toc-text">7.1 移位和循环移位指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-1-%E9%80%BB%E8%BE%91%E4%BB%A5%E4%B8%BA%E5%92%8C%E7%AE%97%E6%95%B0%E7%A7%BB%E4%BD%8D"><span class="toc-number">1.7.1.1.</span> <span class="toc-text">7.1.1 逻辑以为和算数移位</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-2-SHL%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.1.2.</span> <span class="toc-text">7.1.2 SHL指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-3-SHR%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.1.3.</span> <span class="toc-text">7.1.3 SHR指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-4-SAL%E5%92%8CSAR%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.1.4.</span> <span class="toc-text">7.1.4 SAL和SAR指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#AX%E7%AC%A6%E5%8F%B7%E6%89%A9%E5%B1%95%E5%88%B0EAX"><span class="toc-number">1.7.1.4.1.</span> <span class="toc-text">AX符号扩展到EAX</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-5-ROL%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.1.5.</span> <span class="toc-text">7.1.5 ROL指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-6-ROR%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.1.6.</span> <span class="toc-text">7.1.6 ROR指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-7-RCL%E5%92%8CRCR%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.1.7.</span> <span class="toc-text">7.1.7 RCL和RCR指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-8-%E6%9C%89%E7%AC%A6%E5%8F%B7%E6%95%B0%E6%BA%A2%E5%87%BA"><span class="toc-number">1.7.1.8.</span> <span class="toc-text">7.1.8 有符号数溢出</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-1-9-SHLD-x2F-SHRD-%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.1.9.</span> <span class="toc-text">7.1.9 SHLD&#x2F;SHRD 指令</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-2-%E7%A7%BB%E4%BD%8D%E5%92%8C%E5%BE%AA%E7%8E%AF%E7%9A%84%E5%BA%94%E7%94%A8"><span class="toc-number">1.7.2.</span> <span class="toc-text">7.2 移位和循环的应用</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-2-1-%E5%A4%9A%E4%B8%AA%E5%8F%8C%E5%AD%97%E7%9A%84%E7%A7%BB%E4%BD%8D"><span class="toc-number">1.7.2.1.</span> <span class="toc-text">7.2.1 多个双字的移位</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-2-2-%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%B9%98%E6%B3%95"><span class="toc-number">1.7.2.2.</span> <span class="toc-text">7.2.2 二进制乘法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-2-3-%E6%98%BE%E7%A4%BA%E4%BA%8C%E8%BF%9B%E5%88%B6%E4%BD%8D"><span class="toc-number">1.7.2.3.</span> <span class="toc-text">7.2.3 显示二进制位</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-2-4-%E6%8F%90%E5%8F%96%E6%96%87%E4%BB%B6%E6%97%A5%E6%9C%9F%E5%AD%97%E6%AE%B5"><span class="toc-number">1.7.2.4.</span> <span class="toc-text">7.2.4 提取文件日期字段</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-3-%E4%B9%98%E6%B3%95%E5%92%8C%E9%99%A4%E6%B3%95%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.3.</span> <span class="toc-text">7.3 乘法和除法指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-1-MUL%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.3.1.</span> <span class="toc-text">7.3.1 MUL指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-2-IMUL%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.3.2.</span> <span class="toc-text">7.3.2 IMUL指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-3-%E6%B5%8B%E9%87%8F%E7%A8%8B%E5%BA%8F%E8%BF%90%E8%A1%8C%E7%9A%84%E6%97%B6%E9%97%B4"><span class="toc-number">1.7.3.3.</span> <span class="toc-text">7.3.3 测量程序运行的时间</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-4-DIV%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.3.4.</span> <span class="toc-text">7.3.4 DIV指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-5-%E6%9C%89%E7%AC%A6%E5%8F%B7%E6%95%B0%E9%99%A4%E6%B3%95"><span class="toc-number">1.7.3.5.</span> <span class="toc-text">7.3.5 有符号数除法</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E7%AC%A6%E5%8F%B7%E6%89%A9%E5%B1%95%E6%8C%87%E4%BB%A4%EF%BC%88CBW%E3%80%81CWD%E3%80%81CDQ%EF%BC%89"><span class="toc-number">1.7.3.5.1.</span> <span class="toc-text">1.符号扩展指令（CBW、CWD、CDQ）</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-IDIV%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.3.5.2.</span> <span class="toc-text">2.IDIV指令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E9%99%A4%E6%B3%95%E6%BA%A2%E5%87%BA"><span class="toc-number">1.7.3.5.3.</span> <span class="toc-text">3.除法溢出</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-3-6-%E5%AE%9E%E7%8E%B0%E7%AE%97%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-number">1.7.3.6.</span> <span class="toc-text">7.3.6 实现算数表达式</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-4-%E6%89%A9%E5%B1%95%E5%8A%A0%E5%87%8F%E6%B3%95"><span class="toc-number">1.7.4.</span> <span class="toc-text">7.4 扩展加减法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-4-1-ADC%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.4.1.</span> <span class="toc-text">7.4.1 ADC指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-4-2-%E6%89%A9%E5%B1%95%E6%95%B4%E6%95%B0%E5%8A%A0%E6%B3%95%E7%A4%BA%E4%BE%8B"><span class="toc-number">1.7.4.2.</span> <span class="toc-text">7.4.2 扩展整数加法示例</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-4-3-SBB%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.4.3.</span> <span class="toc-text">7.4.3 SBB指令</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-5-ASCII%E5%92%8C%E9%9D%9E%E5%8E%8B%E7%BC%A9%E5%8D%81%E8%BF%9B%E5%88%B6%E8%BF%90%E7%AE%97"><span class="toc-number">1.7.5.</span> <span class="toc-text">7.5 ASCII和非压缩十进制运算</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-5-1-AAA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.5.1.</span> <span class="toc-text">7.5.1 AAA指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-5-2-AAS%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.5.2.</span> <span class="toc-text">7.5.2 AAS指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-5-3-AAM%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.5.3.</span> <span class="toc-text">7.5.3 AAM指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-5-4-AAD%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.5.4.</span> <span class="toc-text">7.5.4 AAD指令</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#7-6-%E5%8E%8B%E7%BC%A9%E5%8D%81%E8%BF%9B%E5%88%B6%E8%AE%A1%E7%AE%97"><span class="toc-number">1.7.6.</span> <span class="toc-text">7.6 压缩十进制计算</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#7-6-1-DAA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.6.1.</span> <span class="toc-text">7.6.1 DAA指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#7-6-2-DAS%E6%8C%87%E4%BB%A4"><span class="toc-number">1.7.6.2.</span> <span class="toc-text">7.6.2 DAS指令</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8-%E9%AB%98%E7%BA%A7%E8%BF%87%E7%A8%8B"><span class="toc-number">1.8.</span> <span class="toc-text">8 高级过程</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#8-2-%E5%A0%86%E6%A0%88%E5%B8%A7"><span class="toc-number">1.8.1.</span> <span class="toc-text">8.2 堆栈帧</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-1-%E5%A0%86%E6%A0%88%E5%8F%82%E6%95%B0"><span class="toc-number">1.8.1.1.</span> <span class="toc-text">8.2.1 堆栈参数</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%80%BC%E4%BC%A0%E9%80%92"><span class="toc-number">1.8.1.1.1.</span> <span class="toc-text">值传递</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%BC%95%E7%94%A8%E4%BC%A0%E9%80%92"><span class="toc-number">1.8.1.1.2.</span> <span class="toc-text">引用传递</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-3-%E8%AE%BF%E9%97%AE%E5%A0%86%E6%A0%88%E5%8F%82%E6%95%B0"><span class="toc-number">1.8.1.2.</span> <span class="toc-text">8.2.3 访问堆栈参数</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E6%98%BE%E5%BC%8F%E7%9A%84%E5%A0%86%E6%A0%88%E5%8F%82%E6%95%B0"><span class="toc-number">1.8.1.2.1.</span> <span class="toc-text">1.显式的堆栈参数</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E6%B8%85%E9%99%A4%E5%A0%86%E6%A0%88"><span class="toc-number">1.8.1.2.2.</span> <span class="toc-text">2.清除堆栈</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-4-32%E4%BD%8D%E8%B0%83%E7%94%A8%E8%A7%84%E8%8C%83"><span class="toc-number">1.8.1.3.</span> <span class="toc-text">8.2.4 32位调用规范</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#C%E8%B0%83%E7%94%A8%E8%A7%84%E8%8C%83"><span class="toc-number">1.8.1.3.1.</span> <span class="toc-text">C调用规范</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#STDCALL%E8%B0%83%E7%94%A8%E8%A7%84%E8%8C%83"><span class="toc-number">1.8.1.3.2.</span> <span class="toc-text">STDCALL调用规范</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-5-%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F"><span class="toc-number">1.8.1.4.</span> <span class="toc-text">8.2.5 局部变量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-6-%E5%BC%95%E7%94%A8%E5%8F%82%E6%95%B0"><span class="toc-number">1.8.1.5.</span> <span class="toc-text">8.2.6 引用参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-7-LEA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.8.1.6.</span> <span class="toc-text">8.2.7 LEA指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-8-ENTER%E5%92%8CLEAVE%E6%8C%87%E4%BB%A4"><span class="toc-number">1.8.1.7.</span> <span class="toc-text">8.2.8 ENTER和LEAVE指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-9-LOCAL%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.8.1.8.</span> <span class="toc-text">8.2.9 LOCAL伪指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-2-10-Microsoft%C3%9764%E8%B0%83%E7%94%A8%E8%A7%84%E8%8C%83"><span class="toc-number">1.8.1.9.</span> <span class="toc-text">8.2.10 Microsoft×64调用规范</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-3-%E9%80%92%E5%BD%92"><span class="toc-number">1.8.2.</span> <span class="toc-text">8.3 递归</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E6%97%A0%E9%99%90%E9%80%92%E5%BD%92"><span class="toc-number">1.8.2.0.1.</span> <span class="toc-text">无限递归</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-1-%E9%80%92%E5%BD%92%E6%B1%82%E5%92%8C"><span class="toc-number">1.8.2.1.</span> <span class="toc-text">8.3.1 递归求和</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-3-2-%E8%AE%A1%E7%AE%97%E9%98%B6%E4%B9%98"><span class="toc-number">1.8.2.2.</span> <span class="toc-text">8.3.2 计算阶乘</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-4-INVOKE%E3%80%81ADDR%E3%80%81PROC%E5%92%8CPROTO"><span class="toc-number">1.8.3.</span> <span class="toc-text">8.4 INVOKE、ADDR、PROC和PROTO</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-1-INVOKE%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.8.3.1.</span> <span class="toc-text">8.4.1 INVOKE伪指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-2-ADDR%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.8.3.2.</span> <span class="toc-text">8.4.2 ADDR伪指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-3-PROC%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.8.3.3.</span> <span class="toc-text">8.4.3 PROC伪指令</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E6%8C%87%E5%AE%9A%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92%E5%8D%8F%E8%AE%AE"><span class="toc-number">1.8.3.3.1.</span> <span class="toc-text">3.指定参数传递协议</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-4-PROTO%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.8.3.4.</span> <span class="toc-text">8.4.4 PROTO伪指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-5-%E5%8F%82%E6%95%B0%E7%B1%BB%E5%88%AB"><span class="toc-number">1.8.3.5.</span> <span class="toc-text">8.4.5 参数类别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-7-%E8%B0%83%E8%AF%95%E6%8F%90%E9%86%92"><span class="toc-number">1.8.3.6.</span> <span class="toc-text">8.4.7 调试提醒</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%8F%82%E6%95%B0%E5%A4%A7%E5%B0%8F%E4%B8%8D%E5%8C%B9%E9%85%8D"><span class="toc-number">1.8.3.6.1.</span> <span class="toc-text">1.参数大小不匹配</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E4%BC%A0%E9%80%92%E9%94%99%E8%AF%AF%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%8C%87%E9%92%88"><span class="toc-number">1.8.3.6.2.</span> <span class="toc-text">2.传递错误类型的指针</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E4%BC%A0%E9%80%92%E7%AB%8B%E5%8D%B3%E6%95%B0"><span class="toc-number">1.8.3.6.3.</span> <span class="toc-text">3.传递立即数</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-4-8-WriteStackFrame%E8%BF%87%E7%A8%8B"><span class="toc-number">1.8.3.7.</span> <span class="toc-text">8.4.8 WriteStackFrame过程</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-5-%E5%88%9B%E5%BB%BA%E5%A4%9A%E6%A8%A1%E5%9D%97%E7%A8%8B%E5%BA%8F"><span class="toc-number">1.8.4.</span> <span class="toc-text">8.5 创建多模块程序</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-5-1-%E9%9A%90%E8%97%8F%E5%92%8C%E5%AF%BC%E5%87%BA%E8%BF%87%E7%A8%8B%E5%90%8D"><span class="toc-number">1.8.4.1.</span> <span class="toc-text">8.5.1 隐藏和导出过程名</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-5-2-%E8%B0%83%E7%94%A8%E5%A4%96%E9%83%A8%E8%BF%87%E7%A8%8B"><span class="toc-number">1.8.4.2.</span> <span class="toc-text">8.5.2 调用外部过程</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-5-3-%E8%B7%A8%E6%A8%A1%E5%9D%97%E4%BD%BF%E7%94%A8%E6%A0%87%E9%87%8F%E5%92%8C%E7%AC%A6%E5%8F%B7"><span class="toc-number">1.8.4.3.</span> <span class="toc-text">8.5.3 跨模块使用标量和符号</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%AF%BC%E5%87%BA%E5%8F%98%E9%87%8F%E5%92%8C%E7%AC%A6%E5%8F%B7"><span class="toc-number">1.8.4.3.1.</span> <span class="toc-text">1.导出变量和符号</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E8%AE%BF%E9%97%AE%E5%A4%96%E9%83%A8%E5%8F%98%E9%87%8F%E5%92%8C%E7%AC%A6%E5%8F%B7"><span class="toc-number">1.8.4.3.2.</span> <span class="toc-text">2.访问外部变量和符号</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E4%BD%BF%E7%94%A8%E5%B8%A6-EXTERNDEF%E7%9A%84INCLUDE%E6%96%87%E4%BB%B6"><span class="toc-number">1.8.4.3.3.</span> <span class="toc-text">3.使用带 EXTERNDEF的INCLUDE文件</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-5-5-%E7%94%A8Extern%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97"><span class="toc-number">1.8.4.4.</span> <span class="toc-text">8.5.5 用Extern新建模块</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-5-6-%E7%94%A8INVOKE%E5%92%8CPROTO%E6%96%B0%E5%BB%BA%E6%A8%A1%E5%9D%97"><span class="toc-number">1.8.4.5.</span> <span class="toc-text">8.5.6 用INVOKE和PROTO新建模块</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-5-7-%E8%AF%BE%E7%A8%8B%E5%9B%9E%E9%A1%BE"><span class="toc-number">1.8.4.6.</span> <span class="toc-text">8.5.7 课程回顾</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-6-%E5%8F%82%E6%95%B0%E7%9A%84%E9%AB%98%E7%BA%A7%E7%94%A8%E6%B3%95%EF%BC%88%E5%8F%AF%E9%80%89%E4%B8%BB%E9%A2%98%EF%BC%89"><span class="toc-number">1.8.5.</span> <span class="toc-text">8.6 参数的高级用法（可选主题）</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#8-6-1-%E5%8F%97USES%E8%BF%90%E7%AE%97%E7%AC%A6%E5%BD%B1%E5%93%8D%E7%9A%84%E5%A0%86%E6%A0%88"><span class="toc-number">1.8.5.1.</span> <span class="toc-text">8.6.1 受USES运算符影响的堆栈</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-6-2-%E5%90%91%E5%A0%86%E6%A0%88%E4%BC%A0%E9%80%928%E4%BD%8D%E5%92%8C16%E4%BD%8D%E5%8F%82%E6%95%B0"><span class="toc-number">1.8.5.2.</span> <span class="toc-text">8.6.2 向堆栈传递8位和16位参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-6-3-%E4%BC%A0%E9%80%9264%E4%BD%8D%E5%8F%82%E6%95%B0"><span class="toc-number">1.8.5.3.</span> <span class="toc-text">8.6.3 传递64位参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#8-6-4-%E9%9D%9E%E5%8F%8C%E5%AD%97%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F"><span class="toc-number">1.8.5.4.</span> <span class="toc-text">8.6.4 非双字局部变量</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-7-Java%E5%AD%97%E8%8A%82%E7%A0%81%EF%BC%88%E5%8F%AF%E9%80%89%E4%B8%BB%E9%A2%98%EF%BC%89"><span class="toc-number">1.8.6.</span> <span class="toc-text">8.7 Java字节码（可选主题）</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#8-8-%E6%9C%AC%E7%AB%A0%E5%B0%8F%E7%BB%93"><span class="toc-number">1.8.7.</span> <span class="toc-text">8.8 本章小结</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#9-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E6%95%B0%E7%BB%84"><span class="toc-number">1.9.</span> <span class="toc-text">9 字符串和数组</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#9-2-%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%9F%BA%E6%9C%AC%E6%8C%87%E4%BB%A4"><span class="toc-number">1.9.1.</span> <span class="toc-text">9.2 字符串基本指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-1-MOVSB%E3%80%81MOVSW%E5%92%8CMOVSD"><span class="toc-number">1.9.1.1.</span> <span class="toc-text">9.2.1 MOVSB、MOVSW和MOVSD</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-2-CMPSB%E3%80%81CMPSW%E5%92%8CCMPSD"><span class="toc-number">1.9.1.2.</span> <span class="toc-text">9.2.2 CMPSB、CMPSW和CMPSD</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-3-SCASB%E3%80%81SCASW%E5%92%8CSCASD"><span class="toc-number">1.9.1.3.</span> <span class="toc-text">9.2.3 SCASB、SCASW和SCASD</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-4-STOSB%E3%80%81STOSW%E5%92%8CSTOSD"><span class="toc-number">1.9.1.4.</span> <span class="toc-text">9.2.4 STOSB、STOSW和STOSD</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-2-5LODSB%E3%80%81LODSW%E5%92%8CLODSD"><span class="toc-number">1.9.1.5.</span> <span class="toc-text">9.2.5LODSB、LODSW和LODSD</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-3-%E9%83%A8%E5%88%86%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BF%87%E7%A8%8B"><span class="toc-number">1.9.2.</span> <span class="toc-text">9.3 部分字符串过程</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-4-%E4%BA%8C%E4%BD%8D%E6%95%B0%E7%BB%84"><span class="toc-number">1.9.3.</span> <span class="toc-text">9.4 二位数组</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-1-%E8%A1%8C%E5%88%97%E9%A1%BA%E5%BA%8F"><span class="toc-number">1.9.3.1.</span> <span class="toc-text">9.4.1 行列顺序</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-2-%E5%9F%BA%E5%9D%80-%E5%8F%98%E5%9D%80%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.9.3.2.</span> <span class="toc-text">9.4.2 基址-变址操作数</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E6%AF%94%E4%BE%8B%E5%9B%A0%E5%AD%90"><span class="toc-number">1.9.3.2.1.</span> <span class="toc-text">2.比例因子</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-3-%E5%9F%BA%E5%9D%80%E4%B8%80%E5%8F%98%E5%9D%80%E4%B8%80%E5%81%8F%E7%A7%BB%E9%87%8F%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.9.3.3.</span> <span class="toc-text">9.4.3 基址一变址一偏移量操作数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-4-4-64%E4%BD%8D%E6%A8%A1%E5%BC%8F%E4%B8%8B%E7%9A%84%E5%9F%BA%E5%9D%80%E4%B8%80%E5%8F%98%E5%9D%80%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.9.3.4.</span> <span class="toc-text">9.4.4 64位模式下的基址一变址操作数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#9-5-%E6%95%B4%E6%95%B0%E6%95%B0%E7%BB%84%E7%9A%84%E6%A3%80%E7%B4%A2%E5%92%8C%E6%8E%92%E5%BA%8F"><span class="toc-number">1.9.4.</span> <span class="toc-text">9.5 整数数组的检索和排序</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#9-5-1-%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F"><span class="toc-number">1.9.4.1.</span> <span class="toc-text">9.5.1 冒泡排序</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-5-2-%E5%AF%B9%E5%8D%8A%E6%9F%A5%E6%89%BE"><span class="toc-number">1.9.4.2.</span> <span class="toc-text">9.5.2 对半查找</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-6-Java%E5%AD%97%E8%8A%82%E7%A0%81%EF%BC%9A%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%A4%84%E7%90%86%EF%BC%88%E5%8F%AF%E9%80%89%E4%B8%BB%E9%A2%98%EF%BC%89"><span class="toc-number">1.9.4.3.</span> <span class="toc-text">9.6 Java字节码：字符串处理（可选主题）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#9-7-%E6%9C%AC%E7%AB%A0%E5%B0%8F%E7%BB%93"><span class="toc-number">1.9.4.4.</span> <span class="toc-text">9.7 本章小结</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#10-%E7%BB%93%E6%9E%84%E5%92%8C%E5%AE%8F"><span class="toc-number">1.10.</span> <span class="toc-text">10 结构和宏</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#10-1-%E7%BB%93%E6%9E%84"><span class="toc-number">1.10.1.</span> <span class="toc-text">10.1 结构</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-1-%E5%AE%9A%E4%B9%89%E7%BB%93%E6%9E%84"><span class="toc-number">1.10.1.1.</span> <span class="toc-text">10.1.1 定义结构</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E5%AF%B9%E9%BD%90%E7%BB%93%E6%9E%84%E5%AD%97%E6%AE%B5"><span class="toc-number">1.10.1.1.1.</span> <span class="toc-text">对齐结构字段</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-2-%E5%A3%B0%E6%98%8E%E7%BB%93%E6%9E%84%E5%8F%98%E9%87%8F"><span class="toc-number">1.10.1.2.</span> <span class="toc-text">10.1.2 声明结构变量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-3-%E5%BC%95%E7%94%A8%E7%BB%93%E6%9E%84%E5%8F%98%E9%87%8F"><span class="toc-number">1.10.1.3.</span> <span class="toc-text">10.1.3 引用结构变量</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E5%BC%95%E7%94%A8%E6%88%90%E5%91%98"><span class="toc-number">1.10.1.3.1.</span> <span class="toc-text">1.引用成员</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E9%97%B4%E6%8E%A5%E5%92%8C%E5%8F%98%E5%9D%80%E6%93%8D%E4%BD%9C%E6%95%B0"><span class="toc-number">1.10.1.3.2.</span> <span class="toc-text">2.间接和变址操作数</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#-1"><span class="toc-number">1.10.1.3.3.</span> <span class="toc-text"></span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E5%AF%B9%E9%BD%90%E7%9A%84%E7%BB%93%E6%9E%84%E6%88%90%E5%91%98%E7%9A%84%E6%80%A7%E8%83%BD"><span class="toc-number">1.10.1.3.4.</span> <span class="toc-text">3.对齐的结构成员的性能</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-5-%E7%BB%93%E6%9E%84%E5%8C%85%E5%90%AB%E7%BB%93%E6%9E%84"><span class="toc-number">1.10.1.4.</span> <span class="toc-text">10.1.5 结构包含结构</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-1-6-%E5%A3%B0%E6%98%8E%E5%92%8C%E4%BD%BF%E7%94%A8%E8%81%94%E5%90%88"><span class="toc-number">1.10.1.5.</span> <span class="toc-text">10.1.6 声明和使用联合</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-2-%E5%AE%8F"><span class="toc-number">1.10.2.</span> <span class="toc-text">10.2 宏</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-1-%E6%A6%82%E8%BF%B0"><span class="toc-number">1.10.2.1.</span> <span class="toc-text">10.2.1 概述</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-2-%E5%AE%9A%E4%B9%89%E5%AE%8F"><span class="toc-number">1.10.2.2.</span> <span class="toc-text">10.2.2 定义宏</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-3-%E8%B0%83%E7%94%A8%E5%AE%8F"><span class="toc-number">1.10.2.3.</span> <span class="toc-text">10.2.3 调用宏</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#%E8%B0%83%E8%AF%95%E5%AE%8F"><span class="toc-number">1.10.2.3.1.</span> <span class="toc-text">调试宏</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-4-%E5%85%B6%E4%BB%96%E5%AE%8F%E7%89%B9%E6%80%A7"><span class="toc-number">1.10.2.4.</span> <span class="toc-text">10.2.4 其他宏特性</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E8%A7%84%E5%AE%9A%E5%BD%A2%E5%8F%82"><span class="toc-number">1.10.2.4.1.</span> <span class="toc-text">1.规定形参</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%AE%8F%E6%B3%A8%E9%87%8A"><span class="toc-number">1.10.2.4.2.</span> <span class="toc-text">2.宏注释</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-ECHO%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.10.2.4.3.</span> <span class="toc-text">3.ECHO伪指令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-LOCAL%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.10.2.4.4.</span> <span class="toc-text">4.LOCAL伪指令</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#5-%E5%8C%85%E5%90%AB%E4%BB%A3%E7%A0%81%E5%92%8C%E6%95%B0%E6%8D%AE%E7%9A%84%E5%AE%8F"><span class="toc-number">1.10.2.4.5.</span> <span class="toc-text">5.包含代码和数据的宏</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#6-%E5%AE%8F%E5%B5%8C%E5%A5%97"><span class="toc-number">1.10.2.4.6.</span> <span class="toc-text">6.宏嵌套</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-5%E4%BD%BF%E7%94%A8%E6%9C%AC%E4%B9%A6%E7%9A%84%E5%AE%8F%E5%BA%93%EF%BC%88%E4%BB%8532%E4%BD%8D%E6%A8%A1%E5%BC%8F%EF%BC%89"><span class="toc-number">1.10.2.5.</span> <span class="toc-text">10.2.5使用本书的宏库（仅32位模式）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-2-7%E6%9C%AC%E8%8A%82%E5%9B%9E%E9%A1%BE"><span class="toc-number">1.10.2.6.</span> <span class="toc-text">10.2.7本节回顾</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-3-%E6%9D%A1%E4%BB%B6%E6%B1%87%E7%BC%96%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.10.3.</span> <span class="toc-text">10.3 条件汇编伪指令</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-1-%E6%A3%80%E6%9F%A5%E7%BC%BA%E5%A4%B1%E7%9A%84%E5%8F%82%E6%95%B0"><span class="toc-number">1.10.3.1.</span> <span class="toc-text">10.3.1 检查缺失的参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-2-%E9%BB%98%E8%AE%A4%E5%8F%82%E6%95%B0%E5%88%9D%E5%A7%8B%E5%80%BC%E8%AE%BE%E5%AE%9A"><span class="toc-number">1.10.3.2.</span> <span class="toc-text">10.3.2 默认参数初始值设定</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-3-%E5%B8%83%E5%B0%94%E8%A1%A8%E8%BE%BE%E5%BC%8F"><span class="toc-number">1.10.3.3.</span> <span class="toc-text">10.3.3 布尔表达式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-4-IF%EF%BC%8CELSE%E5%92%8CENDIF"><span class="toc-number">1.10.3.4.</span> <span class="toc-text">10.3.4 IF，ELSE和ENDIF</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-5-IFIDN%E5%92%8CIFIDNI%E4%BC%AA%E6%8C%87%E4%BB%A4"><span class="toc-number">1.10.3.5.</span> <span class="toc-text">10.3.5 IFIDN和IFIDNI伪指令</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-6-%E7%A4%BA%E4%BE%8B%EF%BC%9A%E7%9F%A9%E9%98%B5%E8%A1%8C%E6%B1%82%E5%92%8C"><span class="toc-number">1.10.3.6.</span> <span class="toc-text">10.3.6 示例：矩阵行求和</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-7-%E7%89%B9%E6%AE%8A%E8%BF%90%E7%AE%97%E7%AC%A6"><span class="toc-number">1.10.3.7.</span> <span class="toc-text">10.3.7 特殊运算符</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#1-%E6%9B%BF%E6%8D%A2%E8%BF%90%E7%AE%97%E7%AC%A6%EF%BC%88-amp-%EF%BC%89"><span class="toc-number">1.10.3.7.1.</span> <span class="toc-text">1.替换运算符（&amp;）</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#2-%E5%B1%95%E5%BC%80%E8%BF%90%E7%AE%97%E7%AC%A6%EF%BC%88-%EF%BC%89"><span class="toc-number">1.10.3.7.2.</span> <span class="toc-text">2.展开运算符（%）</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#3-%E6%96%87%E5%AD%97%E6%96%87%E6%9C%AC%E8%BF%90%E7%AE%97%E7%AC%A6%EF%BC%88-lt-gt-%EF%BC%89"><span class="toc-number">1.10.3.7.3.</span> <span class="toc-text">3.文字文本运算符（&lt;&gt;）</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#4-%E6%96%87%E6%9C%AC%E5%AD%97%E7%AC%A6%E8%BF%90%E7%AE%97%E7%AC%A6%EF%BC%88%EF%BC%81%EF%BC%89"><span class="toc-number">1.10.3.7.4.</span> <span class="toc-text">4.文本字符运算符（！）</span></a></li></ol></li><li class="toc-item toc-level-4"><a class="toc-link" href="#10-3-8-%E5%AE%8F%E5%87%BD%E6%95%B0"><span class="toc-number">1.10.3.8.</span> <span class="toc-text">10.3.8 宏函数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-4-%E5%AE%9A%E4%B9%89%E9%87%8D%E5%A4%8D%E8%AF%AD%E5%8F%A5%E5%9D%97"><span class="toc-number">1.10.4.</span> <span class="toc-text">10.4 定义重复语句块</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#10-4-5-%E7%A4%BA%E4%BE%8B%EF%BC%9A%E9%93%BE%E8%A1%A8"><span class="toc-number">1.10.4.1.</span> <span class="toc-text">10.4.5 示例：链表</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#10-5-%E6%9C%AC%E7%AB%A0%E5%B0%8F%E7%BB%93"><span class="toc-number">1.10.5.</span> <span class="toc-text">10.5 本章小结</span></a></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/posts/3e9f.html" title="RMM观察与初探"><img src="https://z1.ax1x.com/2023/10/21/piF47TA.md.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="RMM观察与初探"/></a><div class="content"><a class="title" href="/posts/3e9f.html" title="RMM观察与初探">RMM观察与初探</a><time datetime="2023-10-21T04:30:00.000Z" title="发表于 2023-10-21 12:30:00">2023-10-21</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/5e44.html" title="计算机网络课设——UDP/TCP/TLS Socket实验"><img src="https://s1.ax1x.com/2023/09/09/pP6qXOU.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="计算机网络课设——UDP/TCP/TLS Socket实验"/></a><div class="content"><a class="title" href="/posts/5e44.html" title="计算机网络课设——UDP/TCP/TLS Socket实验">计算机网络课设——UDP/TCP/TLS Socket实验</a><time datetime="2023-09-09T07:10:00.000Z" title="发表于 2023-09-09 15:10:00">2023-09-09</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/cd44.html" title="JQuery的XSS初探"><img src="https://s1.ax1x.com/2023/09/08/pPyvO0O.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="JQuery的XSS初探"/></a><div class="content"><a class="title" href="/posts/cd44.html" title="JQuery的XSS初探">JQuery的XSS初探</a><time datetime="2023-09-08T04:30:00.000Z" title="发表于 2023-09-08 12:30:00">2023-09-08</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/5862.html" title="生产实习记录"><img src="https://s1.ax1x.com/2023/09/02/pPBH058.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="生产实习记录"/></a><div class="content"><a class="title" href="/posts/5862.html" title="生产实习记录">生产实习记录</a><time datetime="2023-09-02T13:51:00.000Z" title="发表于 2023-09-02 21:51:00">2023-09-02</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/9a9b.html" title="Fedora-CoreOS配置与试用（2023年）"><img src="https://s1.ax1x.com/2023/08/28/pPa8tlF.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Fedora-CoreOS配置与试用（2023年）"/></a><div class="content"><a class="title" href="/posts/9a9b.html" title="Fedora-CoreOS配置与试用（2023年）">Fedora-CoreOS配置与试用（2023年）</a><time datetime="2023-08-28T11:35:00.000Z" title="发表于 2023-08-28 19:35:00">2023-08-28</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2019 - 2023 By MocusEZ</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener external nofollow noreferrer" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener external nofollow noreferrer" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div><div class="footer_custom_text"><a href="http://beian.miit.gov.cn/" rel="external nofollow noreferrer"  style="color:#f72b07" target="_blank">闽ICP备2021003009号</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><a id="to_comment" href="#post-comment" title="直达评论"><i class="fas fa-comments"></i></a><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"><script>function loadWaline () {
  function insertCSS () {
    const link = document.createElement("link")
    link.rel = "stylesheet"
    link.href = "https://cdn.jsdelivr.net/npm/@waline/client/dist/waline.min.css"
    document.head.appendChild(link)
  }

  function initWaline () {
    const waline = Waline.init(Object.assign({
      el: '#waline-wrap',
      serverURL: 'https://waline.mocusez.site',
      pageview: ,
      dark: 'html[data-theme="dark"]',
      path: window.location.pathname,
      comment: false,
    }, null))
  }

  if (typeof Waline === 'function') initWaline()
  else {
    insertCSS()
    getScript('https://cdn.jsdelivr.net/npm/@waline/client/dist/waline.min.js').then(initWaline)
  }
}

if ('Waline' === 'Waline' || !false) {
  if (false) btf.loadComment(document.getElementById('waline-wrap'),loadWaline)
  else setTimeout(loadWaline, 0)
} else {
  function loadOtherComment () {
    loadWaline()
  }
}</script></div><script>(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/1df8ba05.js","daovoice")
</script><script>var isChatBtn = false
daovoice('init', {
  app_id: '1df8ba05',},{
  launcher: { 
     disableLauncherIcon: isChatBtn // 悬浮 ICON 是否显示
  },
});
daovoice('update');

if (isChatBtn) {
  var chatBtnFn = () => {
    var chatBtn = document.getElementById("chat_btn")
    chatBtn.addEventListener("click", function(){
      daovoice('show')
    });
  }
  chatBtnFn()
} else {
  if (false) {
    function chatBtnHide () {
      daovoice('update', {},{
        launcher: { 
        disableLauncherIcon: true // 悬浮 ICON 是否显示
        },
      });
    }
    function chatBtnShow () {
      daovoice('update', {},{
        launcher: { 
        disableLauncherIcon: false // 悬浮 ICON 是否显示
        },
      });
    }
  }
}</script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>